Skip to content

Commit

Permalink
Merge pull request #5372 from tstromberg/driver-conflict
Browse files Browse the repository at this point in the history
Use existing driver by default, improve driver conflict message
  • Loading branch information
tstromberg authored Sep 17, 2019
2 parents 28a1472 + 8fb4ed5 commit eae6ece
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 73 deletions.
167 changes: 95 additions & 72 deletions cmd/minikube/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ const (
memory = "memory"
cpus = "cpus"
humanReadableDiskSize = "disk-size"
vmDriver = "vm-driver"
nfsSharesRoot = "nfs-shares-root"
nfsShare = "nfs-share"
kubernetesVersion = "kubernetes-version"
Expand Down Expand Up @@ -179,7 +178,7 @@ func initKubernetesFlags() {

// initDriverFlags inits the commandline flags for vm drivers
func initDriverFlags() {
startCmd.Flags().String(vmDriver, constants.DefaultVMDriver, fmt.Sprintf("VM driver is one of: %v", constants.SupportedVMDrivers))
startCmd.Flags().String("vm-driver", "", fmt.Sprintf("Driver is one of: %v (defaults to virtualbox)", constants.SupportedVMDrivers))
startCmd.Flags().Bool(disableDriverMounts, false, "Disables the filesystem mounts provided by the hypervisors")

// kvm2
Expand Down Expand Up @@ -278,30 +277,33 @@ func runStart(cmd *cobra.Command, args []string) {
registryMirror = viper.GetStringSlice("registry_mirror")
}

driver := viper.GetString(vmDriver)
if err := cmdcfg.IsValidDriver(runtime.GOOS, driver); err != nil {
exit.WithCodeT(
exit.Failure,
"The driver '{{.driver}}' is not supported on {{.os}}",
out.V{"driver": viper.GetString(vmDriver), "os": runtime.GOOS},
)
oldConfig, err := cfg.Load()
if err != nil && !os.IsNotExist(err) {
exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err})
}

driver := selectDriver(oldConfig)
err = autoSetDriverOptions(driver)
if err != nil {
glog.Errorf("Error autoSetOptions : %v", err)
}

validateConfig()
validateUser()
validateFlags(driver)
validateUser(driver)
installOrUpdateDriver(driver)

k8sVersion, isUpgrade := getKubernetesVersion()
config, err := generateCfgFromFlags(cmd, k8sVersion)
k8sVersion, isUpgrade := getKubernetesVersion(oldConfig)
config, err := generateCfgFromFlags(cmd, k8sVersion, driver)
if err != nil {
exit.WithError("Failed to generate config", err)
}

// For non-"none", the ISO is required to boot, so block until it is downloaded
downloadISO(config)

// With "none", images are persistently stored in Docker, so internal caching isn't necessary.
skipCache(&config)
if driver != constants.DriverNone {
if err := cluster.CacheISO(config.MachineConfig); err != nil {
exit.WithError("Failed to cache ISO", err)
}
}

if viper.GetBool(nativeSSH) {
ssh.SetDefaultClient(ssh.Native)
Expand All @@ -324,7 +326,7 @@ func runStart(cmd *cobra.Command, args []string) {
mRunner, preExists, machineAPI, host := startMachine(&config)
defer machineAPI.Close()
// configure the runtime (docker, containerd, crio)
cr := configureRuntimes(mRunner)
cr := configureRuntimes(mRunner, driver)
showVersionInfo(k8sVersion, cr)
waitCacheImages(&cacheGroup)

Expand All @@ -343,8 +345,11 @@ func runStart(cmd *cobra.Command, args []string) {
if err = loadCachedImagesInConfigFile(); err != nil {
out.T(out.FailureType, "Unable to load cached images from config file.")
}

// special ops for none driver, like change minikube directory.
prepareNone(viper.GetString(vmDriver))
if driver == constants.DriverNone {
prepareNone()
}
if viper.GetBool(waitUntilHealthy) {
if err := bs.WaitCluster(config.KubernetesConfig, viper.GetDuration(waitTimeout)); err != nil {
exit.WithError("Wait failed", err)
Expand Down Expand Up @@ -436,29 +441,6 @@ func startMachine(config *cfg.Config) (runner command.Runner, preExists bool, ma
return runner, preExists, m, host
}

func getKubernetesVersion() (k8sVersion string, isUpgrade bool) {
oldConfig, err := cfg.Load()
if err != nil && !os.IsNotExist(err) {
exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err})
}
return validateKubernetesVersions(oldConfig)
}

func downloadISO(config cfg.Config) {
if viper.GetString(vmDriver) != constants.DriverNone {
if err := cluster.CacheISO(config.MachineConfig); err != nil {
exit.WithError("Failed to cache ISO", err)
}
}
}

func skipCache(config *cfg.Config) {
if viper.GetString(vmDriver) == constants.DriverNone {
viper.Set(cacheImages, false)
config.KubernetesConfig.ShouldLoadCachedImages = false
}
}

func showVersionInfo(k8sVersion string, cr cruntime.Manager) {
version, _ := cr.Version()
out.T(cr.Style(), "Preparing Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}} ...", out.V{"k8sVersion": k8sVersion, "runtime": cr.Name(), "runtimeVersion": version})
Expand All @@ -482,6 +464,56 @@ func showKubectlConnectInfo(kcs *kubeconfig.Settings) {
}
}

func selectDriver(oldConfig *cfg.Config) string {
driver := viper.GetString("vm-driver")
// By default, the driver is whatever we used last time
if driver == "" {
driver = constants.DefaultVMDriver
if oldConfig != nil {
driver = oldConfig.MachineConfig.VMDriver
}
}
if err := cmdcfg.IsValidDriver(runtime.GOOS, driver); err != nil {
exit.WithCodeT(exit.Failure, "The driver '{{.driver}}' is not supported on {{.os}}", out.V{"driver": driver, "os": runtime.GOOS})
}

// Detect if our driver conflicts with a previously created VM. If we run into any errors, just move on.
api, err := machine.NewAPIClient()
if err != nil {
glog.Infof("selectDriver NewAPIClient: %v", err)
return driver
}

exists, err := api.Exists(cfg.GetMachineName())
if err != nil {
glog.Infof("selectDriver api.Exists: %v", err)
return driver
}
if !exists {
return driver
}

h, err := api.Load(cfg.GetMachineName())
if err != nil {
glog.Infof("selectDriver api.Load: %v", err)
return driver
}

if h.Driver.DriverName() == driver {
return driver
}

out.ErrT(out.Conflict, `You have an existing "{{.profile_name}}" VM that was created using the "{{.old_driver}}" driver, and is incompatible with the "{{.driver}}" driver.`,
out.V{"profile_name": cfg.GetMachineName(), "driver": driver, "old_driver": h.Driver.DriverName()})

out.ErrT(out.Workaround, `To proceed, either:
1) Delete the existing VM using: '{{.command}} delete'
or
2) Restart with the existing driver: '{{.command}} start --vm-driver={{.old_driver}}'`, out.V{"command": minikubeCmd(), "old_driver": h.Driver.DriverName()})
exit.WithCodeT(exit.Config, "Exiting due to driver incompatibility")
return ""
}

func selectImageRepository(mirrorCountry string, k8sVersion string) (bool, string, error) {
var tryCountries []string
var fallback string
Expand Down Expand Up @@ -543,25 +575,24 @@ func minikubeCmd() string {
}

// validerUser validates minikube is run by the recommended user (privileged or regular)
func validateUser() {
func validateUser(driver string) {
u, err := user.Current()
if err != nil {
glog.Errorf("Error getting the current user: %v", err)
return
}

d := viper.GetString(vmDriver)
useForce := viper.GetBool(force)

if d == constants.DriverNone && u.Uid != "0" && !useForce {
exit.WithCodeT(exit.Permissions, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.`, out.V{"driver_name": d})
if driver == constants.DriverNone && u.Uid != "0" && !useForce {
exit.WithCodeT(exit.Permissions, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.`, out.V{"driver_name": driver})
}

if d == constants.DriverNone || u.Uid != "0" {
if driver == constants.DriverNone || u.Uid != "0" {
return
}

out.T(out.Stopped, "The {{.driver_name}} driver should not be used with root privileges.", out.V{"driver_name": d})
out.T(out.Stopped, "The {{.driver_name}} driver should not be used with root privileges.", out.V{"driver_name": driver})

_, err = cfg.Load()
if err == nil || !os.IsNotExist(err) {
Expand All @@ -572,18 +603,13 @@ func validateUser() {
}
}

// validateConfig validates the supplied configuration against known bad combinations
func validateConfig() {
// validateFlags validates the supplied flags against known bad combinations
func validateFlags(driver string) {
diskSizeMB := pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize))
if diskSizeMB < pkgutil.CalculateSizeInMB(constants.MinimumDiskSize) && !viper.GetBool(force) {
exit.WithCodeT(exit.Config, "Requested disk size {{.requested_size}} is less than minimum of {{.minimum_size}}", out.V{"requested_size": diskSizeMB, "minimum_size": pkgutil.CalculateSizeInMB(constants.MinimumDiskSize)})
}

err := autoSetOptions(viper.GetString(vmDriver))
if err != nil {
glog.Errorf("Error autoSetOptions : %v", err)
}

memorySizeMB := pkgutil.CalculateSizeInMB(viper.GetString(memory))
if memorySizeMB < pkgutil.CalculateSizeInMB(constants.MinimumMemorySize) && !viper.GetBool(force) {
exit.UsageT("Requested memory allocation {{.requested_size}} is less than the minimum allowed of {{.minimum_size}}", out.V{"requested_size": memorySizeMB, "minimum_size": pkgutil.CalculateSizeInMB(constants.MinimumMemorySize)})
Expand All @@ -594,7 +620,7 @@ func validateConfig() {
}

var cpuCount int
if viper.GetString(vmDriver) == constants.DriverNone {
if driver == constants.DriverNone {
if cfg.GetMachineName() != constants.DefaultMachineName {
exit.WithCodeT(exit.Config, "The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/")
}
Expand Down Expand Up @@ -669,7 +695,7 @@ func waitCacheImages(g *errgroup.Group) {
}

// generateCfgFromFlags generates cfg.Config based on flags and supplied arguments
func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string) (cfg.Config, error) {
func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, driver string) (cfg.Config, error) {
r, err := cruntime.New(cruntime.Config{Type: viper.GetString(containerRuntime)})
if err != nil {
return cfg.Config{}, err
Expand Down Expand Up @@ -736,7 +762,7 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string) (cfg.Config, er
Memory: pkgutil.CalculateSizeInMB(viper.GetString(memory)),
CPUs: viper.GetInt(cpus),
DiskSize: pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize)),
VMDriver: viper.GetString(vmDriver),
VMDriver: driver,
ContainerRuntime: viper.GetString(containerRuntime),
HyperkitVpnKitSock: viper.GetString(vpnkitSock),
HyperkitVSockPorts: viper.GetStringSlice(vsockPorts),
Expand Down Expand Up @@ -781,22 +807,19 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string) (cfg.Config, er
return cfg, nil
}

// autoSetOptions sets the options needed for specific vm-driver automatically.
func autoSetOptions(vmDriver string) error {
// options for none driver
if vmDriver == constants.DriverNone {
// autoSetDriverOptions sets the options needed for specific vm-driver automatically.
func autoSetDriverOptions(driver string) error {
if driver == constants.DriverNone {
if o := none.AutoOptions(); o != "" {
return extraOptions.Set(o)
}
viper.Set(cacheImages, false)
}
return nil
}

// prepareNone prepares the user and host for the joy of the "none" driver
func prepareNone(vmDriver string) {
if vmDriver != constants.DriverNone {
return
}
func prepareNone() {
out.T(out.StartingNone, "Configuring local host environment ...")
if viper.GetBool(cfg.WantNoneDriverWarning) {
out.T(out.Empty, "")
Expand Down Expand Up @@ -875,8 +898,8 @@ func validateNetwork(h *host.Host) string {
return ip
}

// validateKubernetesVersions ensures that the requested version is reasonable
func validateKubernetesVersions(old *cfg.Config) (string, bool) {
// getKubernetesVersion ensures that the requested version is reasonable
func getKubernetesVersion(old *cfg.Config) (string, bool) {
rawVersion := viper.GetString(kubernetesVersion)
isUpgrade := false
if rawVersion == "" {
Expand Down Expand Up @@ -952,15 +975,15 @@ func setupKubeAdm(mAPI libmachine.API, kc cfg.KubernetesConfig) bootstrapper.Boo
}

// configureRuntimes does what needs to happen to get a runtime going.
func configureRuntimes(runner cruntime.CommandRunner) cruntime.Manager {
func configureRuntimes(runner cruntime.CommandRunner, driver string) cruntime.Manager {
config := cruntime.Config{Type: viper.GetString(containerRuntime), Runner: runner}
cr, err := cruntime.New(config)
if err != nil {
exit.WithError("Failed runtime", err)
}

disableOthers := true
if viper.GetString(vmDriver) == constants.DriverNone {
if driver == constants.DriverNone {
disableOthers = false
}
err = cr.Enable(disableOthers)
Expand Down Expand Up @@ -1028,9 +1051,9 @@ func saveConfig(clusterCfg *cfg.Config) error {
return cfg.CreateProfile(viper.GetString(cfg.MachineProfile), clusterCfg)
}

func installOrUpdateDriver(vmDriver string) {
func installOrUpdateDriver(driver string) {
var driverExecutable string
switch vmDriver {
switch driver {
case constants.DriverKvm2:
driverExecutable = fmt.Sprintf("docker-machine-driver-%s", constants.DriverKvm2)
case constants.DriverHyperkit:
Expand Down
2 changes: 1 addition & 1 deletion cmd/minikube/cmd/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestGenerateCfgFromFlagsHTTPProxyHandling(t *testing.T) {
if err := os.Setenv("HTTP_PROXY", test.proxy); err != nil {
t.Fatalf("Unexpected error setting HTTP_PROXY: %v", err)
}
config, err := generateCfgFromFlags(cmd, k8sVersion)
config, err := generateCfgFromFlags(cmd, k8sVersion, "none")
if err != nil {
t.Fatalf("Got unexpected error %v during config generation", err)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/minikube/out/style.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ var styles = map[StyleEnum]style{
Issue: {Prefix: " ▪ ", LowPrefix: lowIndent}, // Indented bullet
Check: {Prefix: "✔️ "},
Celebration: {Prefix: "🎉 "},
Workaround: {Prefix: "👉 ", LowPrefix: lowIndent},

// Specialized purpose styles
ISODownload: {Prefix: "💿 "},
Expand Down
1 change: 1 addition & 0 deletions pkg/minikube/out/style_enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,5 @@ const (
MountOptions
Fileserver
Empty
Workaround
)

0 comments on commit eae6ece

Please sign in to comment.