2019-12-17 23:18:31 +00:00
/ *
Copyright 2019 The Kubernetes Authors All rights reserved .
2019-12-18 00:38:56 +00:00
2019-12-17 23:18:31 +00:00
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
2019-12-18 00:38:56 +00:00
2019-12-17 23:18:31 +00:00
http : //www.apache.org/licenses/LICENSE-2.0
2019-12-18 00:38:56 +00:00
2019-12-17 23:18:31 +00:00
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 kic
import (
2020-12-15 12:55:10 +00:00
"context"
2019-12-17 23:18:31 +00:00
"fmt"
2020-01-24 22:15:48 +00:00
"net"
2019-12-17 23:18:31 +00:00
"os/exec"
2020-11-20 18:57:19 +00:00
"runtime"
2019-12-17 23:18:31 +00:00
"strconv"
"strings"
2020-04-07 21:19:20 +00:00
"sync"
2020-02-20 22:43:24 +00:00
"time"
2019-12-17 23:18:31 +00:00
"github.com/docker/machine/libmachine/drivers"
2020-01-24 02:43:26 +00:00
"github.com/docker/machine/libmachine/ssh"
2019-12-17 23:18:31 +00:00
"github.com/docker/machine/libmachine/state"
2020-01-24 03:20:44 +00:00
"github.com/pkg/errors"
2020-09-29 22:49:41 +00:00
"k8s.io/klog/v2"
2020-10-23 05:10:07 +00:00
2019-12-17 23:18:31 +00:00
pkgdrivers "k8s.io/minikube/pkg/drivers"
2019-12-18 00:04:03 +00:00
"k8s.io/minikube/pkg/drivers/kic/oci"
2020-01-24 03:20:44 +00:00
"k8s.io/minikube/pkg/minikube/assets"
2019-12-17 23:18:31 +00:00
"k8s.io/minikube/pkg/minikube/command"
2019-12-22 05:20:32 +00:00
"k8s.io/minikube/pkg/minikube/constants"
2020-03-23 23:38:09 +00:00
"k8s.io/minikube/pkg/minikube/cruntime"
2020-03-05 02:01:41 +00:00
"k8s.io/minikube/pkg/minikube/download"
2020-09-29 21:27:37 +00:00
"k8s.io/minikube/pkg/minikube/driver"
2020-09-22 00:26:55 +00:00
"k8s.io/minikube/pkg/minikube/out"
2020-04-09 01:20:30 +00:00
"k8s.io/minikube/pkg/minikube/sysinit"
2020-04-16 23:10:44 +00:00
"k8s.io/minikube/pkg/util/retry"
2019-12-17 23:18:31 +00:00
)
2020-02-13 02:11:44 +00:00
// Driver represents a kic driver https://minikube.sigs.k8s.io/docs/reference/drivers/docker
2019-12-17 23:18:31 +00:00
type Driver struct {
* drivers . BaseDriver
* pkgdrivers . CommonDriver
2019-12-18 05:36:37 +00:00
URL string
exec command . Runner
NodeConfig Config
OCIBinary string // docker,podman
2019-12-17 23:18:31 +00:00
}
// NewDriver returns a fully configured Kic driver
func NewDriver ( c Config ) * Driver {
d := & Driver {
BaseDriver : & drivers . BaseDriver {
MachineName : c . MachineName ,
StorePath : c . StorePath ,
} ,
2020-04-28 10:28:00 +00:00
exec : command . NewKICRunner ( c . MachineName , c . OCIBinary ) ,
2019-12-18 05:36:37 +00:00
NodeConfig : c ,
2019-12-21 22:31:39 +00:00
OCIBinary : c . OCIBinary ,
2019-12-17 23:18:31 +00:00
}
return d
}
// Create a host using the driver's config
func ( d * Driver ) Create ( ) error {
2021-02-08 23:15:08 +00:00
ctx := context . Background ( )
2020-01-31 05:01:27 +00:00
params := oci . CreateParams {
2020-05-15 09:33:39 +00:00
Mounts : d . NodeConfig . Mounts ,
2020-01-24 22:15:48 +00:00
Name : d . NodeConfig . MachineName ,
Image : d . NodeConfig . ImageDigest ,
2020-02-14 09:01:53 +00:00
ClusterLabel : oci . ProfileLabelKey + "=" + d . MachineName ,
2020-03-02 23:21:37 +00:00
NodeLabel : oci . NodeLabelKey + "=" + d . NodeConfig . MachineName ,
2020-01-24 22:15:48 +00:00
CPUs : strconv . Itoa ( d . NodeConfig . CPU ) ,
Memory : strconv . Itoa ( d . NodeConfig . Memory ) + "mb" ,
Envs : d . NodeConfig . Envs ,
2020-10-06 11:34:20 +00:00
ExtraArgs : append ( [ ] string { "--expose" , fmt . Sprintf ( "%d" , d . NodeConfig . APIServerPort ) } , d . NodeConfig . ExtraArgs ... ) ,
2020-01-24 22:15:48 +00:00
OCIBinary : d . NodeConfig . OCIBinary ,
APIServerPort : d . NodeConfig . APIServerPort ,
2020-08-10 21:04:41 +00:00
}
2020-10-26 18:52:26 +00:00
networkName := d . NodeConfig . Network
2020-10-23 16:50:23 +00:00
if networkName == "" {
networkName = d . NodeConfig . ClusterName
}
if gateway , err := oci . CreateNetwork ( d . OCIBinary , networkName ) ; err != nil {
2020-09-30 23:42:42 +00:00
out . WarningT ( "Unable to create dedicated network, this might result in cluster IP change after restart: {{.error}}" , out . V { "error" : err } )
2020-10-23 16:50:23 +00:00
} else if gateway != nil {
params . Network = networkName
2020-09-22 00:26:55 +00:00
ip := gateway . To4 ( )
2020-09-28 19:55:02 +00:00
// calculate the container IP based on guessing the machine index
2020-09-29 21:27:37 +00:00
ip [ 3 ] += byte ( driver . IndexFromMachineName ( d . NodeConfig . MachineName ) )
2020-10-06 18:20:51 +00:00
klog . Infof ( "calculated static IP %q for the %q container" , ip . String ( ) , d . NodeConfig . MachineName )
2020-09-22 00:26:55 +00:00
params . IP = ip . String ( )
}
2020-10-27 23:07:50 +00:00
drv := d . DriverName ( )
2020-10-23 05:10:07 +00:00
listAddr := oci . DefaultBindIPV4
2020-10-30 20:44:34 +00:00
if oci . IsExternalDaemonHost ( drv ) {
2020-10-30 20:41:06 +00:00
out . WarningT ( "Listening to 0.0.0.0 on external docker host {{.host}}. Please be advised" ,
2020-10-30 20:44:34 +00:00
out . V { "host" : oci . DaemonHost ( drv ) } )
2020-10-23 05:10:07 +00:00
listAddr = "0.0.0.0"
}
2020-09-22 00:26:55 +00:00
2019-12-18 05:36:37 +00:00
// control plane specific options
2020-10-21 06:10:08 +00:00
params . PortMappings = append ( params . PortMappings ,
oci . PortMapping {
2020-10-23 05:10:07 +00:00
ListenAddress : listAddr ,
2020-10-21 06:10:08 +00:00
ContainerPort : int32 ( params . APIServerPort ) ,
} ,
2020-01-24 01:45:50 +00:00
oci . PortMapping {
2020-10-23 05:10:07 +00:00
ListenAddress : listAddr ,
2020-01-24 01:45:50 +00:00
ContainerPort : constants . SSHPort ,
} ,
2020-01-30 22:30:04 +00:00
oci . PortMapping {
2020-10-23 05:10:07 +00:00
ListenAddress : listAddr ,
2020-01-30 22:30:04 +00:00
ContainerPort : constants . DockerDaemonPort ,
} ,
2020-04-10 13:20:12 +00:00
oci . PortMapping {
2020-10-23 05:10:07 +00:00
ListenAddress : listAddr ,
2020-04-10 23:50:57 +00:00
ContainerPort : constants . RegistryAddonPort ,
2020-04-10 13:20:12 +00:00
} ,
2020-01-24 01:45:50 +00:00
)
2020-03-06 00:42:56 +00:00
2020-04-28 10:28:00 +00:00
exists , err := oci . ContainerExists ( d . OCIBinary , params . Name , true )
2020-03-06 00:42:56 +00:00
if err != nil {
2020-09-29 22:49:41 +00:00
klog . Warningf ( "failed to check if container already exists: %v" , err )
2020-03-06 00:42:56 +00:00
}
2020-03-06 06:31:44 +00:00
if exists {
// if container was created by minikube it is safe to delete and recreate it.
2020-04-28 10:28:00 +00:00
if oci . IsCreatedByMinikube ( d . OCIBinary , params . Name ) {
2020-09-29 22:49:41 +00:00
klog . Info ( "Found already existing abandoned minikube container, will try to delete." )
2021-02-08 23:15:08 +00:00
if err := oci . DeleteContainer ( ctx , d . OCIBinary , params . Name ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Errorf ( "Failed to delete a conflicting minikube container %s. You might need to restart your %s daemon and delete it manually and try again: %v" , params . Name , params . OCIBinary , err )
2020-03-06 00:42:56 +00:00
}
2020-03-06 06:31:44 +00:00
} else {
2020-03-06 06:34:10 +00:00
// The conflicting container name was not created by minikube
// user has a container that conflicts with minikube profile name, will not delete users container.
2020-03-06 18:25:48 +00:00
return errors . Wrapf ( err , "user has a conflicting container name %q with minikube container. Needs to be deleted by user's consent." , params . Name )
2020-03-06 00:42:56 +00:00
}
}
2020-04-08 20:44:04 +00:00
if err := oci . PrepareContainerNode ( params ) ; err != nil {
2020-04-07 21:19:20 +00:00
return errors . Wrap ( err , "setting up container node" )
}
var waitForPreload sync . WaitGroup
2020-07-20 19:53:31 +00:00
waitForPreload . Add ( 1 )
2020-09-30 19:17:58 +00:00
var pErr error
2020-07-20 19:53:31 +00:00
go func ( ) {
defer waitForPreload . Done ( )
// If preload doesn't exist, don't bother extracting tarball to volume
if ! download . PreloadExists ( d . NodeConfig . KubernetesVersion , d . NodeConfig . ContainerRuntime ) {
return
}
t := time . Now ( )
2020-09-29 22:49:41 +00:00
klog . Infof ( "Starting extracting preloaded images to volume ..." )
2020-07-20 19:53:31 +00:00
// Extract preloaded images to container
if err := oci . ExtractTarballToVolume ( d . NodeConfig . OCIBinary , download . TarballPath ( d . NodeConfig . KubernetesVersion , d . NodeConfig . ContainerRuntime ) , params . Name , d . NodeConfig . ImageDigest ) ; err != nil {
2020-09-24 17:03:57 +00:00
if strings . Contains ( err . Error ( ) , "No space left on device" ) {
2020-09-30 19:17:58 +00:00
pErr = oci . ErrInsufficientDockerStorage
return
2020-09-24 17:03:57 +00:00
}
2020-09-29 22:49:41 +00:00
klog . Infof ( "Unable to extract preloaded tarball to volume: %v" , err )
2020-07-20 19:53:31 +00:00
} else {
2020-09-29 22:49:41 +00:00
klog . Infof ( "duration metric: took %f seconds to extract preloaded images to volume" , time . Since ( t ) . Seconds ( ) )
2020-07-20 19:53:31 +00:00
}
} ( )
2020-10-05 15:49:28 +00:00
if pErr == oci . ErrInsufficientDockerStorage {
return pErr
}
2020-04-07 21:19:20 +00:00
2020-03-02 21:33:27 +00:00
if err := oci . CreateContainerNode ( params ) ; err != nil {
2020-01-24 03:20:44 +00:00
return errors . Wrap ( err , "create kic node" )
}
if err := d . prepareSSH ( ) ; err != nil {
return errors . Wrap ( err , "prepare kic ssh" )
}
2020-03-02 21:33:27 +00:00
2020-04-07 21:19:20 +00:00
waitForPreload . Wait ( )
2020-01-24 03:20:44 +00:00
return nil
}
// prepareSSH will generate keys and copy to the container so minikube ssh works
func ( d * Driver ) prepareSSH ( ) error {
2020-01-24 02:43:26 +00:00
keyPath := d . GetSSHKeyPath ( )
2020-09-29 22:49:41 +00:00
klog . Infof ( "Creating ssh key for kic: %s..." , keyPath )
2020-01-24 02:43:26 +00:00
if err := ssh . GenerateSSHKey ( keyPath ) ; err != nil {
return errors . Wrap ( err , "generate ssh key" )
}
2020-01-24 03:20:44 +00:00
2020-04-28 10:28:00 +00:00
cmder := command . NewKICRunner ( d . NodeConfig . MachineName , d . NodeConfig . OCIBinary )
2020-01-24 03:20:44 +00:00
f , err := assets . NewFileAsset ( d . GetSSHKeyPath ( ) + ".pub" , "/home/docker/.ssh/" , "authorized_keys" , "0644" )
2019-12-17 23:18:31 +00:00
if err != nil {
2020-01-24 03:20:44 +00:00
return errors . Wrap ( err , "create pubkey assetfile " )
}
if err := cmder . Copy ( f ) ; err != nil {
return errors . Wrap ( err , "copying pub key" )
2019-12-17 23:18:31 +00:00
}
2020-07-24 15:58:09 +00:00
// Double-check that the container has not crashed so that we may give a better error message
s , err := oci . ContainerStatus ( d . NodeConfig . OCIBinary , d . MachineName )
if err != nil {
return err
}
if s != state . Running {
excerpt := oci . LogContainerDebug ( d . OCIBinary , d . MachineName )
return errors . Wrapf ( oci . ErrExitedUnexpectedly , "container name %q state %s: log: %s" , d . MachineName , s , excerpt )
}
2020-01-24 03:20:44 +00:00
if rr , err := cmder . RunCmd ( exec . Command ( "chown" , "docker:docker" , "/home/docker/.ssh/authorized_keys" ) ) ; err != nil {
return errors . Wrapf ( err , "apply authorized_keys file ownership, output %s" , rr . Output ( ) )
}
2020-11-20 18:57:19 +00:00
if runtime . GOOS == "windows" {
path , _ := exec . LookPath ( "powershell" )
ctx , cancel := context . WithTimeout ( context . Background ( ) , 8 * time . Second )
defer cancel ( )
klog . Infof ( "ensuring only current user has permissions to key file located at : %s..." , keyPath )
// Get the SID of the current user
2020-12-15 12:55:10 +00:00
currentUserSidCmd := exec . CommandContext ( ctx , path , "-NoProfile" , "-NonInteractive" , "([System.Security.Principal.WindowsIdentity]::GetCurrent()).User.Value" )
2020-11-20 18:57:19 +00:00
currentUserSidOut , currentUserSidErr := currentUserSidCmd . CombinedOutput ( )
if currentUserSidErr != nil {
2020-12-09 11:24:19 +00:00
klog . Warningf ( "unable to determine current user's SID. minikube tunnel may not work." )
} else {
icaclsArguments := fmt . Sprintf ( ` "%s" /grant:r *%s:F /inheritancelevel:r ` , keyPath , strings . TrimSpace ( string ( currentUserSidOut ) ) )
2020-12-15 12:55:10 +00:00
icaclsCmd := exec . CommandContext ( ctx , path , "-NoProfile" , "-NonInteractive" , "icacls.exe" , icaclsArguments )
2020-12-09 11:24:19 +00:00
icaclsCmdOut , icaclsCmdErr := icaclsCmd . CombinedOutput ( )
2020-11-20 18:57:19 +00:00
2020-12-09 11:24:19 +00:00
if icaclsCmdErr != nil {
return errors . Wrap ( icaclsCmdErr , "unable to execute icacls to set permissions" )
}
2020-11-20 18:57:19 +00:00
2020-12-15 12:55:10 +00:00
if ! strings . Contains ( string ( icaclsCmdOut ) , "Successfully processed 1 files; Failed processing 0 files" ) {
2020-12-15 12:39:43 +00:00
klog . Errorf ( "icacls failed applying permissions - err - [%s], output - [%s]" , icaclsCmdErr , strings . TrimSpace ( string ( icaclsCmdOut ) ) )
2020-12-09 11:24:19 +00:00
}
2020-11-20 18:57:19 +00:00
}
}
2019-12-17 23:18:31 +00:00
return nil
}
// DriverName returns the name of the driver
func ( d * Driver ) DriverName ( ) string {
2020-03-04 18:37:10 +00:00
if d . NodeConfig . OCIBinary == oci . Podman {
return oci . Podman
2019-12-17 23:18:31 +00:00
}
2020-03-04 18:37:10 +00:00
return oci . Docker
2019-12-17 23:18:31 +00:00
}
// GetIP returns an IP or hostname that this host is available at
func ( d * Driver ) GetIP ( ) ( string , error ) {
2020-01-31 00:20:55 +00:00
ip , _ , err := oci . ContainerIPs ( d . OCIBinary , d . MachineName )
2019-12-17 23:18:31 +00:00
return ip , err
}
2020-07-18 18:02:09 +00:00
// GetExternalIP returns an IP which is accessible from outside
2020-01-31 00:20:55 +00:00
func ( d * Driver ) GetExternalIP ( ) ( string , error ) {
2020-10-30 20:44:34 +00:00
return oci . DaemonHost ( d . DriverName ( ) ) , nil
2020-01-31 00:20:55 +00:00
}
2019-12-17 23:18:31 +00:00
// GetSSHHostname returns hostname for use with ssh
func ( d * Driver ) GetSSHHostname ( ) ( string , error ) {
2020-10-30 20:44:34 +00:00
return oci . DaemonHost ( d . DriverName ( ) ) , nil
2019-12-17 23:18:31 +00:00
}
// GetSSHPort returns port for use with ssh
func ( d * Driver ) GetSSHPort ( ) ( int , error ) {
2020-03-14 15:58:12 +00:00
p , err := oci . ForwardedPort ( d . OCIBinary , d . MachineName , constants . SSHPort )
2020-01-24 07:51:41 +00:00
if err != nil {
2020-01-24 22:15:48 +00:00
return p , errors . Wrap ( err , "get ssh host-port" )
2020-01-24 07:51:41 +00:00
}
2020-01-24 22:15:48 +00:00
return p , nil
}
2020-01-24 22:42:28 +00:00
// GetSSHUsername returns the ssh username
func ( d * Driver ) GetSSHUsername ( ) string {
return "docker"
}
2020-01-24 22:15:48 +00:00
// GetSSHKeyPath returns the ssh key path
func ( d * Driver ) GetSSHKeyPath ( ) string {
if d . SSHKeyPath == "" {
d . SSHKeyPath = d . ResolveStorePath ( "id_rsa" )
}
return d . SSHKeyPath
2019-12-17 23:18:31 +00:00
}
2020-03-13 17:37:29 +00:00
// GetURL returns a Docker URL inside this host
// e.g. tcp://1.2.3.4:2376
// more info https://github.com/docker/machine/blob/b170508bf44c3405e079e26d5fdffe35a64c6972/libmachine/provision/utils.go#L159_L175
2019-12-17 23:18:31 +00:00
func ( d * Driver ) GetURL ( ) ( string , error ) {
2020-03-12 23:01:49 +00:00
ip , err := d . GetIP ( )
if err != nil {
return "" , err
}
url := fmt . Sprintf ( "tcp://%s" , net . JoinHostPort ( ip , "2376" ) )
2020-01-24 22:15:48 +00:00
return url , nil
2019-12-17 23:18:31 +00:00
}
// GetState returns the state that the host is in (running, stopped, etc)
func ( d * Driver ) GetState ( ) ( state . State , error ) {
2020-04-28 10:28:00 +00:00
return oci . ContainerStatus ( d . OCIBinary , d . MachineName , true )
2019-12-17 23:18:31 +00:00
}
// Kill stops a host forcefully, including any containers that we are managing.
func ( d * Driver ) Kill ( ) error {
2020-03-24 03:39:21 +00:00
// on init this doesn't get filled when called from cmd
2020-04-28 10:28:00 +00:00
d . exec = command . NewKICRunner ( d . MachineName , d . OCIBinary )
2020-04-09 01:20:30 +00:00
if err := sysinit . New ( d . exec ) . ForceStop ( "kubelet" ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Warningf ( "couldn't force stop kubelet. will continue with kill anyways: %v" , err )
2020-03-23 21:07:47 +00:00
}
2020-04-16 23:10:44 +00:00
2020-04-28 10:28:00 +00:00
if err := oci . ShutDown ( d . OCIBinary , d . MachineName ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Warningf ( "couldn't shutdown the container, will continue with kill anyways: %v" , err )
2020-04-16 23:10:44 +00:00
}
2020-12-10 18:23:26 +00:00
cr := command . NewExecRunner ( false ) // using exec runner for interacting with dameon.
2020-04-28 10:28:00 +00:00
if _ , err := cr . RunCmd ( oci . PrefixCmd ( exec . Command ( d . NodeConfig . OCIBinary , "kill" , d . MachineName ) ) ) ; err != nil {
2020-04-16 23:10:44 +00:00
return errors . Wrapf ( err , "killing %q" , d . MachineName )
2019-12-17 23:18:31 +00:00
}
return nil
}
// Remove will delete the Kic Node Container
func ( d * Driver ) Remove ( ) error {
2020-04-28 10:28:00 +00:00
if _ , err := oci . ContainerID ( d . OCIBinary , d . MachineName ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Infof ( "could not find the container %s to remove it. will try anyways" , d . MachineName )
2019-12-17 23:18:31 +00:00
}
2020-04-15 03:51:18 +00:00
2021-02-08 23:15:08 +00:00
if err := oci . DeleteContainer ( context . Background ( ) , d . NodeConfig . OCIBinary , d . MachineName ) ; err != nil {
2020-04-15 03:51:18 +00:00
if strings . Contains ( err . Error ( ) , "is already in progress" ) {
2020-04-15 17:17:23 +00:00
return errors . Wrap ( err , "stuck delete" )
2020-01-31 05:36:56 +00:00
}
2020-04-15 03:51:18 +00:00
if strings . Contains ( err . Error ( ) , "No such container:" ) {
2020-04-15 17:17:23 +00:00
return nil // nothing was found to delete.
2020-04-15 03:51:18 +00:00
}
2019-12-17 23:18:31 +00:00
}
2020-04-15 05:20:28 +00:00
2020-04-15 17:17:23 +00:00
// check there be no container left after delete
2020-04-28 10:28:00 +00:00
if id , err := oci . ContainerID ( d . OCIBinary , d . MachineName ) ; err == nil && id != "" {
2020-04-15 05:20:28 +00:00
return fmt . Errorf ( "expected no container ID be found for %q after delete. but got %q" , d . MachineName , id )
}
2020-09-22 00:26:55 +00:00
2020-11-16 16:40:57 +00:00
if err := oci . RemoveNetwork ( d . OCIBinary , d . NodeConfig . ClusterName ) ; err != nil {
2020-10-02 21:10:55 +00:00
klog . Warningf ( "failed to remove network (which might be okay) %s: %v" , d . NodeConfig . ClusterName , err )
2020-09-22 00:26:55 +00:00
}
2019-12-17 23:18:31 +00:00
return nil
}
// Restart a host
func ( d * Driver ) Restart ( ) error {
s , err := d . GetState ( )
if err != nil {
2020-09-29 22:49:41 +00:00
klog . Warningf ( "get state during restart: %v" , err )
2019-12-17 23:18:31 +00:00
}
2020-04-16 23:10:44 +00:00
if s == state . Stopped { // don't stop if already stopped
2019-12-17 23:18:31 +00:00
return d . Start ( )
}
2020-04-16 23:10:44 +00:00
if err = d . Stop ( ) ; err != nil {
return fmt . Errorf ( "stop during restart %v" , err )
}
if err = d . Start ( ) ; err != nil {
return fmt . Errorf ( "start during restart %v" , err )
}
return nil
2019-12-17 23:18:31 +00:00
}
2020-04-16 23:10:44 +00:00
// Start an already created kic container
2019-12-17 23:18:31 +00:00
func ( d * Driver ) Start ( ) error {
2020-05-04 20:16:59 +00:00
if err := oci . StartContainer ( d . NodeConfig . OCIBinary , d . MachineName ) ; err != nil {
2020-06-18 01:32:11 +00:00
oci . LogContainerDebug ( d . OCIBinary , d . MachineName )
2020-06-17 22:07:17 +00:00
_ , err := oci . DaemonInfo ( d . OCIBinary )
if err != nil {
2020-06-18 01:32:11 +00:00
return errors . Wrapf ( oci . ErrDaemonInfo , "debug daemon info %q" , d . MachineName )
2020-06-17 22:07:17 +00:00
}
2020-04-16 23:20:04 +00:00
return errors . Wrap ( err , "start" )
2019-12-17 23:18:31 +00:00
}
2020-04-16 23:10:44 +00:00
checkRunning := func ( ) error {
2020-04-28 10:28:00 +00:00
s , err := oci . ContainerStatus ( d . NodeConfig . OCIBinary , d . MachineName )
2020-04-16 23:10:44 +00:00
if err != nil {
return err
}
if s != state . Running {
return fmt . Errorf ( "expected container state be running but got %q" , s )
2019-12-17 23:18:31 +00:00
}
2020-09-29 22:49:41 +00:00
klog . Infof ( "container %q state is running." , d . MachineName )
2019-12-17 23:18:31 +00:00
return nil
}
2020-04-16 23:10:44 +00:00
if err := retry . Expo ( checkRunning , 500 * time . Microsecond , time . Second * 30 ) ; err != nil {
2020-07-24 15:58:09 +00:00
excerpt := oci . LogContainerDebug ( d . OCIBinary , d . MachineName )
2020-06-17 22:07:17 +00:00
_ , err := oci . DaemonInfo ( d . OCIBinary )
if err != nil {
return errors . Wrapf ( oci . ErrDaemonInfo , "container name %q" , d . MachineName )
}
2020-07-24 15:58:09 +00:00
return errors . Wrapf ( oci . ErrExitedUnexpectedly , "container name %q: log: %s" , d . MachineName , excerpt )
2020-04-16 23:10:44 +00:00
}
return nil
2019-12-17 23:18:31 +00:00
}
// Stop a host gracefully, including any containers that we are managing.
func ( d * Driver ) Stop ( ) error {
2020-03-24 03:39:21 +00:00
// on init this doesn't get filled when called from cmd
2020-04-28 10:28:00 +00:00
d . exec = command . NewKICRunner ( d . MachineName , d . OCIBinary )
2020-03-23 20:34:36 +00:00
// docker does not send right SIG for systemd to know to stop the systemd.
2020-03-23 20:41:15 +00:00
// to avoid bind address be taken on an upgrade. more info https://github.com/kubernetes/minikube/issues/7171
2020-04-09 01:20:30 +00:00
if err := sysinit . New ( d . exec ) . Stop ( "kubelet" ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Warningf ( "couldn't stop kubelet. will continue with stop anyways: %v" , err )
2020-04-09 01:20:30 +00:00
if err := sysinit . New ( d . exec ) . ForceStop ( "kubelet" ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Warningf ( "couldn't force stop kubelet. will continue with stop anyways: %v" , err )
2020-03-23 23:38:09 +00:00
}
}
runtime , err := cruntime . New ( cruntime . Config { Type : d . NodeConfig . ContainerRuntime , Runner : d . exec } )
if err != nil { // won't return error because:
// even though we can't stop the cotainers inside, we still wanna stop the minikube container itself
2020-09-29 22:49:41 +00:00
klog . Errorf ( "unable to get container runtime: %v" , err )
2020-03-23 23:38:09 +00:00
} else {
containers , err := runtime . ListContainers ( cruntime . ListOptions { Namespaces : constants . DefaultNamespaces } )
if err != nil {
2020-09-29 22:49:41 +00:00
klog . Infof ( "unable list containers : %v" , err )
2020-03-23 23:38:09 +00:00
}
if len ( containers ) > 0 {
if err := runtime . StopContainers ( containers ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Infof ( "unable to stop containers : %v" , err )
2020-04-10 03:01:11 +00:00
}
if err := runtime . KillContainers ( containers ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Errorf ( "unable to kill containers : %v" , err )
2020-03-23 23:38:09 +00:00
}
}
2020-09-29 22:49:41 +00:00
klog . Infof ( "successfully stopped kubernetes!" )
2020-03-23 23:38:09 +00:00
2020-03-23 20:34:36 +00:00
}
2020-04-10 04:50:09 +00:00
if err := killAPIServerProc ( d . exec ) ; err != nil {
2020-09-29 22:49:41 +00:00
klog . Warningf ( "couldn't stop kube-apiserver proc: %v" , err )
2020-04-10 03:53:15 +00:00
}
2020-04-28 10:28:00 +00:00
cmd := exec . Command ( d . NodeConfig . OCIBinary , "stop" , d . MachineName )
2019-12-17 23:18:31 +00:00
if err := cmd . Run ( ) ; err != nil {
return errors . Wrapf ( err , "stopping %s" , d . MachineName )
}
return nil
}
2020-04-15 05:20:28 +00:00
// RunSSHCommandFromDriver implements direct ssh control to the driver
func ( d * Driver ) RunSSHCommandFromDriver ( ) error {
return fmt . Errorf ( "driver does not support RunSSHCommandFromDriver commands" )
}
2020-04-10 04:50:09 +00:00
// killAPIServerProc will kill an api server proc if it exists
// to ensure this never happens https://github.com/kubernetes/minikube/issues/7521
func killAPIServerProc ( runner command . Runner ) error {
// first check if it exists
rr , err := runner . RunCmd ( exec . Command ( "pgrep" , "kube-apiserver" ) )
if err == nil { // this means we might have a running kube-apiserver
pid , err := strconv . Atoi ( rr . Stdout . String ( ) )
if err == nil { // this means we have a valid pid
2020-09-29 22:49:41 +00:00
klog . Warningf ( "Found a kube-apiserver running with pid %d, will try to kill the proc" , pid )
2020-09-28 19:40:14 +00:00
if _ , err = runner . RunCmd ( exec . Command ( "pkill" , "-9" , fmt . Sprint ( pid ) ) ) ; err != nil {
2020-04-10 04:50:09 +00:00
return errors . Wrap ( err , "kill" )
}
}
}
return nil
}