未验证 提交 e2bbf711 编写于 作者: M Medya Ghazizadeh 提交者: GitHub

Merge branch 'master' into NewCmdRunner

......@@ -9,12 +9,11 @@ env:
- GOPROXY=https://proxy.golang.org
matrix:
include:
- language: python
name: Check Boilerplate
- language: go
name: Check Boilerplate
go: 1.12.12
env:
- TESTSUITE=boilerplate
before_install:
- pip install flake8 && flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
script: make test
- language: go
......@@ -36,6 +35,8 @@ matrix:
script: make test
after_success:
- bash <(curl -s https://codecov.io/bash)
travisBuddy:
regex: (FAIL:|\.go:\d+:|^panic:|failed$)
notifications:
webhooks:
urls:
......
# Release Notes
## Version 1.5.0 - 2019-10-25
* Default to best-available local hypervisor rather than VirtualBox [#5700](https://github.com/kubernetes/minikube/pull/5700)
* Update default Kubernetes version to v1.16.2 [#5731](https://github.com/kubernetes/minikube/pull/5731)
* Add json output for status [#5611](https://github.com/kubernetes/minikube/pull/5611)
* gvisor: Use chroot instead of LD_LIBRARY_PATH [#5735](https://github.com/kubernetes/minikube/pull/5735)
* Hide innocuous viper ConfigFileNotFoundError [#5732](https://github.com/kubernetes/minikube/pull/5732)
Thank you to our contributors!
- Anders F Björklund
- duohedron
- Javis Zhou
- Josh Woodcock
- Kenta Iso
- Marek Schwarz
- Medya Ghazizadeh
- Nanik T
- Rob Bruce
- Sharif Elgamal
- Thomas Strömberg
## Version 1.5.0-beta.0 - 2019-10-21
* Fix node InternalIP not matching host-only address [#5427](https://github.com/kubernetes/minikube/pull/5427)
* Add helm-tiller addon [#5363](https://github.com/kubernetes/minikube/pull/5363)
* Add ingress-dns addon [#5507](https://github.com/kubernetes/minikube/pull/5507)
* Add validation checking for minikube profile [#5624](https://github.com/kubernetes/minikube/pull/5624)
* add ability to override autoupdating drivers [#5640](https://github.com/kubernetes/minikube/pull/5640)
* Add option to configure dnsDomain in kubeAdm [#5566](https://github.com/kubernetes/minikube/pull/5566)
* Added flags to purge configuration with minikube delete [#5548](https://github.com/kubernetes/minikube/pull/5548)
* Upgrade Buildroot to 2019.02 and VirtualBox to 5.2 [#5609](https://github.com/kubernetes/minikube/pull/5609)
* Add libmachine debug logs back [#5574](https://github.com/kubernetes/minikube/pull/5574)
* Add JSON output for addons list [#5601](https://github.com/kubernetes/minikube/pull/5601)
* Update default Kubernetes version to 1.16.1 [#5593](https://github.com/kubernetes/minikube/pull/5593)
* Upgrade nginx ingress controller to 0.26.1 [#5514](https://github.com/kubernetes/minikube/pull/5514)
* Initial translations for fr, es, de, ja, and zh-CN [#5466](https://github.com/kubernetes/minikube/pull/5466)
* PL translation [#5491](https://github.com/kubernetes/minikube/pull/5491)
* Warn if incompatible kubectl version is in use [#5596](https://github.com/kubernetes/minikube/pull/5596)
* Fix crash when deleting the cluster but it doesn't exist [#4980](https://github.com/kubernetes/minikube/pull/4980)
* Add json output for profile list [#5554](https://github.com/kubernetes/minikube/pull/5554)
* Allow addon enabling and disabling when minikube is not running [#5565](https://github.com/kubernetes/minikube/pull/5565)
* Added option to delete all profiles [#4780](https://github.com/kubernetes/minikube/pull/4780)
* Replace registry-creds addon ReplicationController with Deployment [#5586](https://github.com/kubernetes/minikube/pull/5586)
* Performance and security enhancement for ingress-dns addon [#5614](https://github.com/kubernetes/minikube/pull/5614)
* Add addons flag to 'minikube start' in order to enable specified addons [#5543](https://github.com/kubernetes/minikube/pull/5543)
* Warn when a user tries to set a profile name that is unlikely to be valid [#4999](https://github.com/kubernetes/minikube/pull/4999)
* Make error message more human readable [#5563](https://github.com/kubernetes/minikube/pull/5563)
* Adjusted Terminal Style Detection [#5508](https://github.com/kubernetes/minikube/pull/5508)
* Fixes image repository flags when using CRI-O and containerd runtime [#5447](https://github.com/kubernetes/minikube/pull/5447)
* fix "minikube update-context" command fail [#5626](https://github.com/kubernetes/minikube/pull/5626)
* Fix pods not being scheduled when ingress deployment is patched [#5519](https://github.com/kubernetes/minikube/pull/5519)
* Fix order of parameters to CurrentContext funcs [#5439](https://github.com/kubernetes/minikube/pull/5439)
* Add solution for VERR_VMX_MSR_ALL_VMX_DISABLED [#5460](https://github.com/kubernetes/minikube/pull/5460)
* fr: fix translations of environment & existent [#5483](https://github.com/kubernetes/minikube/pull/5483)
* optimizing Chinese translation [#5201](https://github.com/kubernetes/minikube/pull/5201)
* Change systemd unit files perm to 644 [#5492](https://github.com/kubernetes/minikube/pull/5492)
Huge thank you for this release towards our contributors:
- Anders F Björklund
- bhanu011
- chentanjun
- Cornelius Weig
- Doug A
- hwdef
- James Peach
- Josh Woodcock
- Kenta Iso
- Marcin Niemira
- Medya Ghazizadeh
- Nanik T
- Pranav Jituri
- Samuel Almeida
- serhatcetinkaya
- Sharif Elgamal
- tanjunchen
- Thomas Strömberg
- u5surf
- yugo horie
- yuxiaobo
- Zhongcheng Lao
- Zoltán Reegn
## Version 1.4.0 - 2019-09-17
Notable user-facing changes:
......
......@@ -15,7 +15,7 @@
# Bump these on release - and please check ISO_VERSION for correctness.
VERSION_MAJOR ?= 1
VERSION_MINOR ?= 5
VERSION_BUILD ?= 0-beta.0
VERSION_BUILD ?= 0
RAW_VERSION=$(VERSION_MAJOR).$(VERSION_MINOR).${VERSION_BUILD}
VERSION ?= v$(RAW_VERSION)
......@@ -62,6 +62,8 @@ GOLINT_OPTIONS = --timeout 4m \
--enable goimports,gocritic,golint,gocyclo,misspell,nakedret,stylecheck,unconvert,unparam,dogsled \
--exclude 'variable on range scope.*in function literal|ifElseChain'
# Major version of gvisor image. Increment when there are breaking changes.
GVISOR_IMAGE_VERSION ?= 2
export GO111MODULE := on
......@@ -480,11 +482,11 @@ out/gvisor-addon: pkg/minikube/assets/assets.go pkg/minikube/translate/translati
.PHONY: gvisor-addon-image
gvisor-addon-image: out/gvisor-addon
docker build -t $(REGISTRY)/gvisor-addon:latest -f deploy/gvisor/Dockerfile .
docker build -t $(REGISTRY)/gvisor-addon:$(GVISOR_IMAGE_VERSION) -f deploy/gvisor/Dockerfile .
.PHONY: push-gvisor-addon-image
push-gvisor-addon-image: gvisor-addon-image
gcloud docker -- push $(REGISTRY)/gvisor-addon:latest
gcloud docker -- push $(REGISTRY)/gvisor-addon:$(GVISOR_IMAGE_VERSION)
.PHONY: release-iso
release-iso: minikube_iso checksum
......
......@@ -201,12 +201,6 @@ var settings = []Setting{
validations: []setFn{IsValidAddon},
callbacks: []setFn{EnableOrDisableAddon},
},
{
name: "default-storageclass",
set: SetBool,
validations: []setFn{IsValidAddon},
callbacks: []setFn{EnableOrDisableStorageClasses},
},
{
name: "storage-provisioner",
set: SetBool,
......
......@@ -22,11 +22,11 @@ import (
"k8s.io/minikube/pkg/minikube/assets"
pkgConfig "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
)
var minikubeConfig = pkgConfig.MinikubeConfig{
"vm-driver": constants.DriverKvm2,
"vm-driver": driver.KVM2,
"cpus": 12,
"show-libmachine-logs": true,
}
......@@ -49,7 +49,7 @@ func TestFindSetting(t *testing.T) {
}
func TestSetString(t *testing.T) {
err := SetString(minikubeConfig, "vm-driver", constants.DriverVirtualbox)
err := SetString(minikubeConfig, "vm-driver", driver.VirtualBox)
if err != nil {
t.Fatalf("Couldn't set string: %v", err)
}
......
......@@ -28,8 +28,8 @@ import (
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/cruntime"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/out"
)
......@@ -44,13 +44,11 @@ and then start minikube again with the following flags:
minikube start --container-runtime=containerd --docker-opt containerd=/var/run/containerd/containerd.sock`
// IsValidDriver checks if a driver is supported
func IsValidDriver(string, driver string) error {
for _, d := range constants.SupportedVMDrivers {
if driver == d {
return nil
}
func IsValidDriver(string, name string) error {
if driver.Supported(name) {
return nil
}
return fmt.Errorf("driver %q is not supported", driver)
return fmt.Errorf("driver %q is not supported", name)
}
// RequiresRestartMsg returns the "requires restart" message
......
......@@ -35,6 +35,7 @@ import (
"k8s.io/minikube/pkg/minikube/cluster"
pkg_config "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/kubeconfig"
"k8s.io/minikube/pkg/minikube/localpath"
......@@ -190,8 +191,7 @@ func deleteProfile(profile *pkg_config.Profile) error {
return DeletionError{Err: delErr, Errtype: MissingProfile}
}
// In the case of "none", we want to uninstall Kubernetes as there is no VM to delete
if err == nil && cc.MachineConfig.VMDriver == constants.DriverNone {
if err == nil && driver.BareMetal(cc.MachineConfig.VMDriver) {
if err := uninstallKubernetes(api, cc.KubernetesConfig, viper.GetString(cmdcfg.Bootstrapper)); err != nil {
deletionError, ok := err.(DeletionError)
if ok {
......
......@@ -35,7 +35,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
)
......@@ -343,7 +343,7 @@ var dockerEnvCmd = &cobra.Command{
if err != nil {
exit.WithError("Error getting host", err)
}
if host.Driver.DriverName() == constants.DriverNone {
if host.Driver.DriverName() == driver.None {
exit.UsageT(`'none' driver does not support 'minikube docker-env' command`)
}
hostSt, err := cluster.GetHostStatus(api)
......
......@@ -31,7 +31,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/out"
......@@ -107,7 +107,7 @@ var mountCmd = &cobra.Command{
if err != nil {
exit.WithError("Error loading api", err)
}
if host.Driver.DriverName() == constants.DriverNone {
if host.Driver.DriverName() == driver.None {
exit.UsageT(`'none' driver does not support 'minikube mount' command`)
}
var ip net.IP
......
......@@ -235,9 +235,11 @@ func initConfig() {
configPath := localpath.ConfigFile
viper.SetConfigFile(configPath)
viper.SetConfigType("json")
err := viper.ReadInConfig()
if err != nil {
glog.Warningf("Error reading config file at %s: %v", configPath, err)
if err := viper.ReadInConfig(); err != nil {
// This config file is optional, so don't emit errors if missing
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
glog.Warningf("Error reading config file at %s: %v", configPath, err)
}
}
setupViper()
}
......
......@@ -25,7 +25,7 @@ import (
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/out"
......@@ -46,7 +46,7 @@ var sshCmd = &cobra.Command{
if err != nil {
exit.WithError("Error getting host", err)
}
if host.Driver.DriverName() == constants.DriverNone {
if host.Driver.DriverName() == driver.None {
exit.UsageT("'none' driver does not support 'minikube ssh' command")
}
if viper.GetBool(nativeSSH) {
......
......@@ -39,13 +39,13 @@ import (
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/pkg/errors"
"github.com/shirou/gopsutil/cpu"
gopshost "github.com/shirou/gopsutil/host"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/sync/errgroup"
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
"k8s.io/minikube/pkg/drivers"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
"k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm"
......@@ -54,7 +54,7 @@ import (
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/cruntime"
"k8s.io/minikube/pkg/minikube/drivers/none"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/kubeconfig"
"k8s.io/minikube/pkg/minikube/localpath"
......@@ -63,6 +63,7 @@ import (
"k8s.io/minikube/pkg/minikube/notify"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/proxy"
"k8s.io/minikube/pkg/minikube/translate"
pkgutil "k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/lock"
"k8s.io/minikube/pkg/util/retry"
......@@ -133,18 +134,6 @@ var (
extraOptions cfg.ExtraOptionSlice
)
type kubectlversion struct {
CVersion VersionInfo `json:"clientVersion"`
SVersion VersionInfo `json:"serverVersion"`
}
// VersionInfo holds version information
type VersionInfo struct {
Major string `json:"major"`
Minor string `json:"minor"`
GitVersion string `json:"gitVersion"`
}
func init() {
initMinikubeFlags()
initKubernetesFlags()
......@@ -206,7 +195,7 @@ func initKubernetesFlags() {
// initDriverFlags inits the commandline flags for vm drivers
func initDriverFlags() {
startCmd.Flags().String("vm-driver", "", fmt.Sprintf("Driver is one of: %v (defaults to virtualbox)", constants.SupportedVMDrivers))
startCmd.Flags().String("vm-driver", "", fmt.Sprintf("Driver is one of: %v (defaults to auto-detect)", driver.SupportedDrivers()))
startCmd.Flags().Bool(disableDriverMounts, false, "Disables the filesystem mounts provided by the hypervisors")
// kvm2
......@@ -300,30 +289,33 @@ func runStart(cmd *cobra.Command, args []string) {
exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err})
}
driver := selectDriver(oldConfig)
err = autoSetDriverOptions(driver)
driverName := selectDriver(oldConfig)
glog.Infof("selected: %v", driverName)
err = autoSetDriverOptions(cmd, driverName)
if err != nil {
glog.Errorf("Error autoSetOptions : %v", err)
}
validateFlags(driver)
validateUser(driver)
validateFlags(driverName)
validateUser(driverName)
v, err := version.GetSemverVersion()
if err != nil {
out.WarningT("Error parsing minikube version: {{.error}}", out.V{"error": err})
} else if err := drivers.InstallOrUpdate(driver, localpath.MakeMiniPath("bin"), v, viper.GetBool(interactive), viper.GetBool(autoUpdate)); err != nil {
out.WarningT("Unable to update {{.driver}} driver: {{.error}}", out.V{"driver": driver, "error": err})
// No need to install a driver in download-only mode
if !viper.GetBool(downloadOnly) {
v, err := version.GetSemverVersion()
if err != nil {
out.WarningT("Error parsing minikube version: {{.error}}", out.V{"error": err})
} else if err := driver.InstallOrUpdate(driverName, localpath.MakeMiniPath("bin"), v, viper.GetBool(interactive), viper.GetBool(autoUpdate)); err != nil {
out.WarningT("Unable to update {{.driver}} driver: {{.error}}", out.V{"driver": driverName, "error": err})
}
}
k8sVersion, isUpgrade := getKubernetesVersion(oldConfig)
config, err := generateCfgFromFlags(cmd, k8sVersion, driver)
config, err := generateCfgFromFlags(cmd, k8sVersion, driverName)
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
if driver != constants.DriverNone {
if !driver.BareMetal(driverName) {
if err := cluster.CacheISO(config.MachineConfig); err != nil {
exit.WithError("Failed to cache ISO", err)
}
......@@ -350,7 +342,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, driver, config.KubernetesConfig)
cr := configureRuntimes(mRunner, driverName, config.KubernetesConfig)
showVersionInfo(k8sVersion, cr)
waitCacheImages(&cacheGroup)
......@@ -379,8 +371,8 @@ func runStart(cmd *cobra.Command, args []string) {
out.T(out.FailureType, "Unable to load cached images from config file.")
}
// special ops for none driver, like change minikube directory.
if driver == constants.DriverNone {
// special ops for none , like change minikube directory.
if driverName == driver.None {
prepareNone()
}
if viper.GetBool(waitUntilHealthy) {
......@@ -388,7 +380,9 @@ func runStart(cmd *cobra.Command, args []string) {
exit.WithError("Wait failed", err)
}
}
showKubectlConnectInfo(kubeconfig)
if err := showKubectlInfo(kubeconfig, k8sVersion); err != nil {
glog.Errorf("kubectl info: %v", err)
}
}
func displayVersion(version string) {
......@@ -499,16 +493,7 @@ func showVersionInfo(k8sVersion string, cr cruntime.Manager) {
}
}
/**
Function to check for kubectl. The checking is to compare
the version reported by both the client and server. Checking
is based on what is outlined in Kubernetes document
https://kubernetes.io/docs/setup/release/version-skew-policy/#kubectl
*/
func showKubectlConnectInfo(kcs *kubeconfig.Settings) {
var output []byte
clientVersion := kubectlversion{}
func showKubectlInfo(kcs *kubeconfig.Settings, k8sVersion string) error {
if kcs.KeepContext {
out.T(out.Kubectl, "To connect to this cluster, use: kubectl --context={{.name}}", out.V{"name": kcs.ClusterName})
} else {
......@@ -516,76 +501,107 @@ func showKubectlConnectInfo(kcs *kubeconfig.Settings) {
}
path, err := exec.LookPath("kubectl")
// ...not found just print and return
if err != nil {
out.T(out.Tip, "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/")
return
return nil
}
output, err = exec.Command(path, "version", "--output=json").Output()
j, err := exec.Command(path, "version", "--client", "--output=json").Output()
if err != nil {
return
return errors.Wrap(err, "exec")
}
glog.Infof("Received output from kubectl %s", output)
// unmarshal the json
output = []byte("Nanik")
clientjsonErr := json.Unmarshal(output, &clientVersion)
if clientjsonErr != nil {
glog.Infof("There was an error processing kubectl json output.")
return
cv := struct {
ClientVersion struct {
GitVersion string `json:"gitVersion"`
} `json:"clientVersion"`
}{}
err = json.Unmarshal(j, &cv)
if err != nil {
return errors.Wrap(err, "unmarshal")
}
// obtain the minor version for both client & server
serverMinor, _ := strconv.Atoi(clientVersion.SVersion.Minor)
clientMinor, _ := strconv.Atoi(clientVersion.CVersion.Minor)
if math.Abs(float64(clientMinor-serverMinor)) > 1 {
out.T(out.Tip, "{{.path}} is version {{.clientMinor}}, and is incompatible with your specified Kubernetes version. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster",
out.V{"path": path, "clientMinor": clientMinor})
client, err := semver.Make(strings.TrimPrefix(cv.ClientVersion.GitVersion, version.VersionPrefix))
if err != nil {
return errors.Wrap(err, "client semver")
}
cluster := semver.MustParse(strings.TrimPrefix(k8sVersion, version.VersionPrefix))
minorSkew := int(math.Abs(float64(int(client.Minor) - int(cluster.Minor))))
glog.Infof("kubectl: %s, cluster: %s (minor skew: %d)", client, cluster, minorSkew)
if client.Major != cluster.Major || minorSkew > 1 {
out.WarningT("{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster",
out.V{"path": path, "client_version": client, "cluster_version": cluster})
}
return nil
}
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.DriverVirtualbox
name := viper.GetString("vm-driver")
glog.Infof("selectDriver: flag=%q, old=%v", name, oldConfig)
if name == "" {
// By default, the driver is whatever we used last time
if oldConfig != nil {
driver = oldConfig.MachineConfig.VMDriver
return oldConfig.MachineConfig.VMDriver
}
options := driver.Choices()
pick, alts := driver.Choose(options)
if len(options) > 1 {
out.T(out.Sparkle, `Automatically selected the '{{.driver}}' driver (alternates: {{.alternates}})`, out.V{"driver": pick.Name, "alternates": alts})
} else {
out.T(out.Sparkle, `Automatically selected the '{{.driver}}' driver`, out.V{"driver": pick.Name})
}
if pick.Name == "" {
exit.WithCodeT(exit.Config, "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/")
}
name = pick.Name
}
if !driver.Supported(name) {
exit.WithCodeT(exit.Failure, "The driver '{{.driver}}' is not supported on {{.os}}", out.V{"driver": name, "os": runtime.GOOS})
}
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})
st := driver.Status(name)
if st.Error != nil {
out.ErrLn("")
out.WarningT("'{{.driver}}' driver reported a possible issue: {{.error}}", out.V{"driver": name, "error": st.Error, "fix": st.Fix})
out.ErrT(out.Tip, "Suggestion: {{.fix}}", out.V{"fix": translate.T(st.Fix)})
if st.Doc != "" {
out.ErrT(out.Documentation, "Documentation: {{.url}}", out.V{"url": st.Doc})
}
out.ErrLn("")
}
// 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
return name
}
exists, err := api.Exists(cfg.GetMachineName())
if err != nil {
glog.Infof("selectDriver api.Exists: %v", err)
return driver
return name
}
if !exists {
return driver
return name
}
h, err := api.Load(cfg.GetMachineName())
if err != nil {
glog.Infof("selectDriver api.Load: %v", err)
return driver
return name
}
if h.Driver.DriverName() == driver || h.Driver.DriverName() == "not-found" {
return driver
if h.Driver.DriverName() == name || h.Driver.DriverName() == "not-found" {
return name
}
out.ErrT(out.Conflict, `The 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.V{"profile_name": cfg.GetMachineName(), "driver": name, "old_driver": h.Driver.DriverName()})
out.ErrT(out.Workaround, `To proceed, either:
1) Delete the existing VM using: '{{.command}} delete'
......@@ -655,7 +671,7 @@ func minikubeCmd() string {
}
// validerUser validates minikube is run by the recommended user (privileged or regular)
func validateUser(driver string) {
func validateUser(drvName string) {
u, err := user.Current()
if err != nil {
glog.Errorf("Error getting the current user: %v", err)
......@@ -664,15 +680,15 @@ func validateUser(driver string) {
useForce := viper.GetBool(force)
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 driver.BareMetal(drvName) && 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": drvName})
}
if driver == constants.DriverNone || u.Uid != "0" {
if driver.BareMetal(drvName) || u.Uid != "0" {
return
}
out.T(out.Stopped, `The "{{.driver_name}}" driver should not be used with root privileges.`, out.V{"driver_name": driver})
out.T(out.Stopped, `The "{{.driver_name}}" driver should not be used with root privileges.`, out.V{"driver_name": drvName})
out.T(out.Tip, "If you are running minikube within a VM, consider using --vm-driver=none:")
out.T(out.Documentation, " https://minikube.sigs.k8s.io/docs/reference/drivers/none/")
......@@ -689,7 +705,7 @@ func validateUser(driver string) {
}
// validateFlags validates the supplied flags against known bad combinations
func validateFlags(driver string) {
func validateFlags(drvName string) {
diskSizeMB := pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize))
if diskSizeMB < pkgutil.CalculateSizeInMB(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(minimumDiskSize)})
......@@ -705,7 +721,7 @@ func validateFlags(driver string) {
}
var cpuCount int
if driver == constants.DriverNone {
if driver.BareMetal(drvName) {
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/")
}
......@@ -780,7 +796,7 @@ func waitCacheImages(g *errgroup.Group) {
}
// generateCfgFromFlags generates cfg.Config based on flags and supplied arguments
func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, driver string) (cfg.Config, error) {
func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) (cfg.Config, error) {
r, err := cruntime.New(cruntime.Config{Type: viper.GetString(containerRuntime)})
if err != nil {
return cfg.Config{}, err
......@@ -832,7 +848,7 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, driver string)
Memory: pkgutil.CalculateSizeInMB(viper.GetString(memory)),
CPUs: viper.GetInt(cpus),
DiskSize: pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize)),
VMDriver: driver,
VMDriver: drvName,
ContainerRuntime: viper.GetString(containerRuntime),
HyperkitVpnKitSock: viper.GetString(vpnkitSock),
HyperkitVSockPorts: viper.GetStringSlice(vsockPorts),
......@@ -896,12 +912,14 @@ func setDockerProxy() {
}
// 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)
func autoSetDriverOptions(cmd *cobra.Command, drvName string) error {
hints := driver.FlagDefaults(drvName)
if !cmd.Flags().Changed("extra-config") && hints.ExtraOptions != "" {
return extraOptions.Set(hints.ExtraOptions)
}
if !cmd.Flags().Changed(cacheImages) {
viper.Set(cacheImages, hints.CacheImages)
}
return nil
}
......@@ -985,8 +1003,7 @@ func validateNetwork(h *host.Host, r command.Runner) string {
}
}
// none driver does not need ssh access
if h.Driver.DriverName() != constants.DriverNone {
if driver.BareMetal(h.Driver.DriverName()) {
sshAddr := fmt.Sprintf("%s:22", ip)
conn, err := net.Dial("tcp", sshAddr)
if err != nil {
......@@ -1111,7 +1128,7 @@ 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, driver string, k8s cfg.KubernetesConfig) cruntime.Manager {
func configureRuntimes(runner cruntime.CommandRunner, drvName string, k8s cfg.KubernetesConfig) cruntime.Manager {
config := cruntime.Config{Type: viper.GetString(containerRuntime), Runner: runner, ImageRepository: k8s.ImageRepository, KubernetesVersion: k8s.KubernetesVersion}
cr, err := cruntime.New(config)
if err != nil {
......@@ -1119,7 +1136,7 @@ func configureRuntimes(runner cruntime.CommandRunner, driver string, k8s cfg.Kub
}
disableOthers := true
if driver == constants.DriverNone {
if driver.BareMetal(drvName) {
disableOthers = false
}
err = cr.Enable(disableOthers)
......
......@@ -17,7 +17,10 @@ limitations under the License.
package cmd
import (
"encoding/json"
"fmt"
"os"
"strings"
"text/template"
"github.com/docker/machine/libmachine/state"
......@@ -35,6 +38,15 @@ import (
)
var statusFormat string
var output string
var KubeconfigStatus = struct {
Configured string
Misconfigured string
}{
Configured: `Configured`,
Misconfigured: `Misconfigured`,
}
// Status represents the status
type Status struct {
......@@ -51,7 +63,7 @@ const (
defaultStatusFormat = `host: {{.Host}}
kubelet: {{.Kubelet}}
apiserver: {{.APIServer}}
kubectl: {{.Kubeconfig}}
kubeconfig: {{.Kubeconfig}}
`
)
......@@ -63,6 +75,11 @@ var statusCmd = &cobra.Command{
Exit status contains the status of minikube's VM, cluster and kubernetes encoded on it's bits in this order from right to left.
Eg: 7 meaning: 1 (for minikube NOK) + 2 (for cluster NOK) + 4 (for kubernetes NOK)`,
Run: func(cmd *cobra.Command, args []string) {
if output != "text" && statusFormat != defaultStatusFormat {
exit.UsageT("Cannot use both --output and --format options")
}
var returnCode = 0
api, err := machine.NewAPIClient()
if err != nil {
......@@ -115,10 +132,9 @@ var statusCmd = &cobra.Command{
glog.Errorln("Error kubeconfig status:", err)
}
if ks {
kubeconfigSt = "Correctly Configured: pointing to minikube-vm at " + ip.String()
kubeconfigSt = KubeconfigStatus.Configured
} else {
kubeconfigSt = "Misconfigured: pointing to stale minikube-vm." +
"\nTo fix the kubectl context, run minikube update-context"
kubeconfigSt = KubeconfigStatus.Misconfigured
returnCode |= k8sNotRunningStatusFlag
}
} else {
......@@ -131,13 +147,14 @@ var statusCmd = &cobra.Command{
APIServer: apiserverSt,
Kubeconfig: kubeconfigSt,
}
tmpl, err := template.New("status").Parse(statusFormat)
if err != nil {
exit.WithError("Error creating status template", err)
}
err = tmpl.Execute(os.Stdout, status)
if err != nil {
exit.WithError("Error executing status template", err)
switch strings.ToLower(output) {
case "text":
printStatusText(status)
case "json":
printStatusJSON(status)
default:
exit.WithCodeT(exit.BadUsage, fmt.Sprintf("invalid output format: %s. Valid values: 'text', 'json'", output))
}
os.Exit(returnCode)
......@@ -145,7 +162,32 @@ var statusCmd = &cobra.Command{
}
func init() {
statusCmd.Flags().StringVar(&statusFormat, "format", defaultStatusFormat,
statusCmd.Flags().StringVarP(&statusFormat, "format", "f", defaultStatusFormat,
`Go template format string for the status output. The format for Go templates can be found here: https://golang.org/pkg/text/template/
For the list accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status`)
statusCmd.Flags().StringVarP(&output, "output", "o", "text",
`minikube status --output OUTPUT. json, text`)
}
var printStatusText = func(status Status) {
tmpl, err := template.New("status").Parse(statusFormat)
if err != nil {
exit.WithError("Error creating status template", err)
}
err = tmpl.Execute(os.Stdout, status)
if err != nil {
exit.WithError("Error executing status template", err)
}
if status.Kubeconfig == KubeconfigStatus.Misconfigured {
out.WarningT("Warning: Your kubectl is pointing to stale minikube-vm.\nTo fix the kubectl context, run `minikube update-context`")
}
}
var printStatusJSON = func(status Status) {
jsonString, err := json.Marshal(status)
if err != nil {
exit.WithError("Error converting status to json", err)
}
out.String(string(jsonString))
}
......@@ -28,6 +28,9 @@ import (
// Fix for https://github.com/kubernetes/minikube/issues/4866
_ "k8s.io/minikube/pkg/initflag"
// Register drivers
_ "k8s.io/minikube/pkg/minikube/registry/drvs"
mlog "github.com/docker/machine/libmachine/log"
"github.com/golang/glog"
......
......@@ -24,50 +24,28 @@ spec:
hostPID: true
containers:
- name: gvisor
image: {{default "gcr.io/k8s-minikube" .ImageRepository}}/gvisor-addon:latest
image: {{default "gcr.io/k8s-minikube" .ImageRepository}}/gvisor-addon:2
securityContext:
privileged: true
volumeMounts:
- mountPath: /node/
name: node
- mountPath: /usr/libexec/sudo
name: sudo
- mountPath: /var/run
name: varrun
- mountPath: /usr/bin
name: usrbin
- mountPath: /usr/lib
name: usrlib
- mountPath: /bin
name: bin
name: node-root
- mountPath: /node/run
name: node-run
- mountPath: /tmp/gvisor
name: gvisor
name: node-tmp
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/node/bin
- name: SYSTEMD_IGNORE_CHROOT
value: "yes"
imagePullPolicy: IfNotPresent
volumes:
- name: node
- name: node-root
hostPath:
path: /
- name: sudo
- name: node-run
hostPath:
path: /usr/libexec/sudo
- name: varrun
hostPath:
path: /var/run
- name: usrlib
hostPath:
path: /usr/lib
- name: usrbin
hostPath:
path: /usr/bin
- name: bin
hostPath:
path: /bin
- name: gvisor
path: /run
- name: node-tmp
hostPath:
path: /tmp/gvisor
restartPolicy: Always
{{ define "main" }}
<div style="padding-top:20px">
{{ .Render "content" }}
</div>
{{ end }}
\ No newline at end of file
{{ define "main" }}
<div style="padding-top:20px">
{{ .Render "content" }}
</div>
{{ end }}
\ No newline at end of file
{{ define "main" }}
<div style="padding-top:60px">
{{ .Render "content" }}
</div>
{{ end }}
\ No newline at end of file
{{ define "main" }}
<div style="padding-top:20px">
{{ .Render "content" }}
</div>
{{ end }}
\ No newline at end of file
......@@ -12,9 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM ubuntu:18.04
RUN apt-get update && \
apt-get install -y kmod gcc wget xz-utils libc6-dev bc libelf-dev bison flex openssl libssl-dev libidn2-0 sudo libcap2 && \
rm -rf /var/lib/apt/lists/*
# Need an image with chroot
FROM alpine:3
COPY out/gvisor-addon /gvisor-addon
CMD ["/gvisor-addon"]
[
{
"name": "v1.5.0",
"checksums": {
"darwin": "eb716c176f404bb555966ff3947d5d9c5fb63eb902d11c83839fda492ff4b1fc",
"linux": "ca50dcc7c83d4dde484d650a5a1934ea1bef692340af3aa831d34c6e847b2770",
"windows": "bdd61e446f49570428848ad15337264edfecc55d1dd4aed4499d559f9c8383b9"
}
},
{
"name": "v1.4.0",
"checksums": {
......
/*
Copyright 2019 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 main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strings"
)
var (
boilerplatedir = flag.String("boilerplate-dir", ".", "Boilerplate directory for boilerplate files")
rootdir = flag.String("rootdir", "../../", "Root directory to examine")
verbose = flag.Bool("v", false, "Verbose")
skippedPaths = regexp.MustCompile(`Godeps|third_party|_gopath|_output|\.git|cluster/env.sh|vendor|test/e2e/generated/bindata.go|site/themes/docsy`)
windowdNewLine = regexp.MustCompile(`\r`)
txtExtension = regexp.MustCompile(`\.txt`)
goBuildTag = regexp.MustCompile(`(?m)^(// \+build.*\n)+\n`)
shebang = regexp.MustCompile(`(?m)^(#!.*\n)\n*`)
copyright = regexp.MustCompile(`Copyright YEAR`)
copyrightReal = regexp.MustCompile(`Copyright \d{4}`)
)
func main() {
flag.Parse()
refs, err := extensionToBoilerplate(*boilerplatedir)
if err != nil {
log.Fatal(err)
}
if len(refs) == 0 {
log.Fatal("no references in ", *boilerplatedir)
}
files, err := filesToCheck(*rootdir, refs)
if err != nil {
log.Fatal(err)
}
for _, file := range files {
pass, err := filePasses(file, refs[filepath.Ext(file)])
if err != nil {
log.Println(err)
}
if !pass {
path, err := filepath.Abs(file)
if err != nil {
log.Println(err)
}
fmt.Println(path)
}
}
}
// extensionToBoilerplate returns a map of file extension to required boilerplate text.
func extensionToBoilerplate(dir string) (map[string][]byte, error) {
refs := make(map[string][]byte)
files, _ := filepath.Glob(dir + "/*.txt")
for _, filename := range files {
extension := strings.ToLower(filepath.Ext(txtExtension.ReplaceAllString(filename, "")))
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
refs[extension] = windowdNewLine.ReplaceAll(data, nil)
}
if *verbose {
dir, err := filepath.Abs(dir)
if err != nil {
return refs, err
}
fmt.Printf("Found %v boilerplates in %v for the following extensions:", len(refs), dir)
for ext := range refs {
fmt.Printf(" %v", ext)
}
fmt.Println()
}
return refs, nil
}
// filePasses checks whether the processed file is valid. Returning false means that the file does not the proper boilerplate template.
func filePasses(filename string, expectedBoilerplate []byte) (bool, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return false, err
}
data = windowdNewLine.ReplaceAll(data, nil)
extension := filepath.Ext(filename)
// remove build tags from the top of Go files
if extension == ".go" {
data = goBuildTag.ReplaceAll(data, nil)
}
// remove shebang from the top of shell files
if extension == ".sh" {
data = shebang.ReplaceAll(data, nil)
}
// if our test file is smaller than the reference it surely fails!
if len(data) < len(expectedBoilerplate) {
return false, nil
}
data = data[:len(expectedBoilerplate)]
// Search for "Copyright YEAR" which exists in the boilerplate, but shouldn't in the real thing
if copyright.Match(data) {
return false, nil
}
// Replace all occurrences of the regex "Copyright \d{4}" with "Copyright YEAR"
data = copyrightReal.ReplaceAll(data, []byte(`Copyright YEAR`))
return bytes.Equal(data, expectedBoilerplate), nil
}
// filesToCheck returns the list of the filers that will be checked for the boilerplate.
func filesToCheck(rootDir string, extensions map[string][]byte) ([]string, error) {
var outFiles []string
err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
// remove current workdir from the beginig of the path in case it matches the skipped path
cwd, _ := os.Getwd()
// replace "\" with "\\" for windows style path
re := regexp.MustCompile(`\\`)
re = regexp.MustCompile(`^` + re.ReplaceAllString(cwd, `\\`))
if !info.IsDir() && !skippedPaths.MatchString(re.ReplaceAllString(filepath.Dir(path), "")) {
if extensions[strings.ToLower(filepath.Ext(path))] != nil {
outFiles = append(outFiles, path)
}
}
return nil
})
if err != nil {
return nil, err
}
if *verbose {
rootDir, err = filepath.Abs(rootDir)
if err != nil {
return outFiles, err
}
fmt.Printf("Found %v files to check in %v\n\n", len(outFiles), rootDir)
}
return outFiles, nil
}
#!/usr/bin/env python
# Copyright 2015 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.
from __future__ import print_function
import argparse
import glob
import json
import mmap
import os
import re
import sys
parser = argparse.ArgumentParser()
parser.add_argument("filenames", help="list of files to check, all files if unspecified", nargs='*')
rootdir = os.path.dirname(__file__) + "/../../"
rootdir = os.path.abspath(rootdir)
parser.add_argument("--rootdir", default=rootdir, help="root directory to examine")
default_boilerplate_dir = os.path.join(rootdir, "hack/boilerplate")
parser.add_argument("--boilerplate-dir", default=default_boilerplate_dir)
args = parser.parse_args()
def get_refs():
refs = {}
for path in glob.glob(os.path.join(args.boilerplate_dir, "boilerplate.*.txt")):
extension = os.path.basename(path).split(".")[1]
ref_file = open(path, 'r')
ref = ref_file.read().splitlines()
ref_file.close()
refs[extension] = ref
return refs
def file_passes(filename, refs, regexs):
try:
f = open(filename, 'r')
except:
return False
data = f.read()
f.close()
basename = os.path.basename(filename)
extension = file_extension(filename)
if extension != "":
ref = refs[extension]
else:
ref = refs[basename]
# remove build tags from the top of Go files
if extension == "go":
p = regexs["go_build_constraints"]
(data, found) = p.subn("", data, 1)
# remove shebang from the top of shell files
if extension == "sh":
p = regexs["shebang"]
(data, found) = p.subn("", data, 1)
data = data.splitlines()
# if our test file is smaller than the reference it surely fails!
if len(ref) > len(data):
return False
# trim our file to the same number of lines as the reference file
data = data[:len(ref)]
p = regexs["year"]
for d in data:
if p.search(d):
return False
# Replace all occurrences of the regex "2018|2017|2016|2015|2014" with "YEAR"
p = regexs["date"]
for i, d in enumerate(data):
(data[i], found) = p.subn('YEAR', d)
if found != 0:
break
# if we don't match the reference at this point, fail
if ref != data:
return False
return True
def file_extension(filename):
return os.path.splitext(filename)[1].split(".")[-1].lower()
skipped_dirs = ['Godeps', 'third_party', '_gopath', '_output', '.git', 'cluster/env.sh', "vendor", "test/e2e/generated/bindata.go"]
def normalize_files(files):
newfiles = []
for pathname in files:
if any(x in pathname for x in skipped_dirs):
continue
newfiles.append(pathname)
for i, pathname in enumerate(newfiles):
if not os.path.isabs(pathname):
newfiles[i] = os.path.join(rootdir, pathname)
return newfiles
def get_files(extensions):
files = []
if len(args.filenames) > 0:
files = args.filenames
else:
for root, dirs, walkfiles in os.walk(args.rootdir):
# don't visit certain dirs. This is just a performance improvement
# as we would prune these later in normalize_files(). But doing it
# cuts down the amount of filesystem walking we do and cuts down
# the size of the file list
for d in skipped_dirs:
if d in dirs:
dirs.remove(d)
for name in walkfiles:
pathname = os.path.join(root, name)
files.append(pathname)
files = normalize_files(files)
outfiles = []
for pathname in files:
basename = os.path.basename(pathname)
extension = file_extension(pathname)
if extension in extensions or basename in extensions:
outfiles.append(pathname)
return outfiles
def get_regexs():
regexs = {}
# Search for "YEAR" which exists in the boilerplate, but shouldn't in the real thing
regexs["year"] = re.compile( 'YEAR' )
# dates can be 2010 to 2039
regexs["date"] = re.compile( '(20[123]\d)' )
# strip // +build \n\n build constraints
regexs["go_build_constraints"] = re.compile(r"^(// \+build.*\n)+\n", re.MULTILINE)
# strip #!.* from shell scripts
regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE)
return regexs
def main():
regexs = get_regexs()
refs = get_refs()
filenames = get_files(refs.keys())
for filename in filenames:
if not file_passes(filename, refs, regexs):
print(filename, file=sys.stdout)
if __name__ == "__main__":
sys.exit(main())
......@@ -21,7 +21,9 @@ function prepend() {
local pattern=$1
local ref=$2
local headers=$3
local files=$(hack/boilerplate/boilerplate.py --rootdir ${ROOT_DIR} | grep -v "$ignore" | grep "$pattern")
pushd hack/boilerplate > /dev/null
local files=$(go run boilerplate.go -rootdir ${ROOT_DIR} -boilerplate-dir ${ROOT_DIR}/hack/boilerplate | grep -v "$ignore" | grep "$pattern")
popd > /dev/null
for f in ${files}; do
echo ${f};
local copyright="$(cat hack/boilerplate/boilerplate.${ref}.txt | sed s/YEAR/$(date +%Y)/g)"
......
......@@ -165,7 +165,7 @@ if type -P vboxmanage; then
vboxmanage unregistervm "${guid}" || true
done
ifaces=$(vboxmanage list hostonlyifs | grep -E "^Name:" | awk '{ printf $2 }')
ifaces=$(vboxmanage list hostonlyifs | grep -E "^Name:" | awk '{ print $2 }')
for if in $ifaces; do
vboxmanage hostonlyif remove "${if}" || true
done
......@@ -245,22 +245,25 @@ mkdir -p "${TEST_HOME}"
export MINIKUBE_HOME="${TEST_HOME}/.minikube"
export KUBECONFIG="${TEST_HOME}/kubeconfig"
# Build the gvisor image. This will be copied into minikube and loaded by ctr.
# Used by TestContainerd for Gvisor Test.
# TODO: move this to integration test setup.
# Build the gvisor image so that we can integration test changes to pkg/gvisor
chmod +x ./testdata/gvisor-addon
# skipping gvisor mac because ofg https://github.com/kubernetes/minikube/issues/5137
if [ "$(uname)" != "Darwin" ]; then
docker build -t gcr.io/k8s-minikube/gvisor-addon:latest -f testdata/gvisor-addon-Dockerfile ./testdata
# Should match GVISOR_IMAGE_VERSION in Makefile
docker build -t gcr.io/k8s-minikube/gvisor-addon:2 -f testdata/gvisor-addon-Dockerfile ./testdata
fi
echo ""
echo ">> Starting ${E2E_BIN} at $(date)"
set -x
${SUDO_PREFIX}${E2E_BIN} \
-minikube-start-args="--vm-driver=${VM_DRIVER} ${EXTRA_START_ARGS}" \
-expected-default-driver="${EXPECTED_DEFAULT_DRIVER}" \
-test.timeout=60m \
-test.parallel=${PARALLEL_COUNT} \
-binary="${MINIKUBE_BIN}" && result=$? || result=$?
set +x
echo ">> ${E2E_BIN} exited with ${result} at $(date)"
echo ""
......
......@@ -29,6 +29,7 @@ OS_ARCH="linux-amd64"
VM_DRIVER="kvm2"
JOB_NAME="KVM_Linux"
PARALLEL_COUNT=4
EXPECTED_DEFAULT_DRIVER="kvm2"
# Download files and set permissions
source ./common.sh
......@@ -31,6 +31,7 @@ VM_DRIVER="none"
JOB_NAME="none_Linux"
EXTRA_ARGS="--bootstrapper=kubeadm"
PARALLEL_COUNT=1
EXPECTED_DEFAULT_DRIVER="kvm2"
SUDO_PREFIX="sudo -E "
export KUBECONFIG="/root/.kube/config"
......
......@@ -29,6 +29,7 @@ OS_ARCH="linux-amd64"
VM_DRIVER="virtualbox"
JOB_NAME="VirtualBox_Linux"
PARALLEL_COUNT=4
EXPECTED_DEFAULT_DRIVER="kvm2"
# Download files and set permissions
source ./common.sh
......@@ -32,6 +32,8 @@ JOB_NAME="HyperKit_macOS"
EXTRA_ARGS="--bootstrapper=kubeadm"
EXTRA_START_ARGS=""
PARALLEL_COUNT=3
EXPECTED_DEFAULT_DRIVER="hyperkit"
# Download files and set permissions
source common.sh
......@@ -30,6 +30,10 @@ VM_DRIVER="virtualbox"
JOB_NAME="VirtualBox_macOS"
EXTRA_ARGS="--bootstrapper=kubeadm"
PARALLEL_COUNT=3
# hyperkit behaves better, so it has higher precedence.
# Assumes that hyperkit is also installed on the VirtualBox CI host.
EXPECTED_DEFAULT_DRIVER="hyperkit"
# Download files and set permissions
source common.sh
......@@ -19,7 +19,7 @@ gsutil.cmd -m cp -r gs://minikube-builds/$env:MINIKUBE_LOCATION/testdata .
./out/minikube-windows-amd64.exe delete
out/e2e-windows-amd64.exe -minikube-start-args="--vm-driver=hyperv --hyperv-virtual-switch=primary-virtual-switch" -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=65m
out/e2e-windows-amd64.exe --expected-default-driver=hyperv -minikube-start-args="--vm-driver=hyperv --hyperv-virtual-switch=primary-virtual-switch" -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=65m
$env:result=$lastexitcode
# If the last exit code was 0->success, x>0->error
If($env:result -eq 0){$env:status="success"}
......
......@@ -19,7 +19,7 @@ gsutil.cmd -m cp -r gs://minikube-builds/$env:MINIKUBE_LOCATION/testdata .
./out/minikube-windows-amd64.exe delete
out/e2e-windows-amd64.exe -minikube-start-args="--vm-driver=virtualbox" -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=30m
out/e2e-windows-amd64.exe -minikube-start-args="--vm-driver=virtualbox" -expected-default-driver=hyperv -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=30m
$env:result=$lastexitcode
# If the last exit code was 0->success, x>0->error
If($env:result -eq 0){$env:status="success"}
......
......@@ -4,7 +4,7 @@ publish = "site/public/"
command = "pwd && cd themes/docsy && git submodule update -f --init && cd ../.. && hugo"
[build.environment]
HUGO_VERSION = "0.55.6"
HUGO_VERSION = "0.59.0"
[context.production.environment]
HUGO_ENV = "production"
......
/*
Copyright 2016 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 drivers
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"syscall"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/mcnflag"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/golang/glog"
"github.com/pkg/errors"
)
// This file is for common code shared among internal machine drivers
// Code here should not be called from within minikube
// GetDiskPath returns the path of the machine disk image
func GetDiskPath(d *drivers.BaseDriver) string {
return filepath.Join(d.ResolveStorePath("."), d.GetMachineName()+".rawdisk")
}
// CommonDriver is the common driver base class
type CommonDriver struct{}
// GetCreateFlags is not implemented yet
func (d *CommonDriver) GetCreateFlags() []mcnflag.Flag {
return nil
}
// SetConfigFromFlags is not implemented yet
func (d *CommonDriver) SetConfigFromFlags(flags drivers.DriverOptions) error {
return nil
}
func createRawDiskImage(sshKeyPath, diskPath string, diskSizeMb int) error {
tarBuf, err := mcnutils.MakeDiskImage(sshKeyPath)
if err != nil {
return errors.Wrap(err, "make disk image")
}
file, err := os.OpenFile(diskPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
if err != nil {
return errors.Wrap(err, "open")
}
defer file.Close()
if _, err := file.Seek(0, io.SeekStart); err != nil {
return errors.Wrap(err, "seek")
}
if _, err := file.Write(tarBuf.Bytes()); err != nil {
return errors.Wrap(err, "write tar")
}
if err := file.Close(); err != nil {
return errors.Wrapf(err, "closing file %s", diskPath)
}
if err := os.Truncate(diskPath, int64(diskSizeMb*1000000)); err != nil {
return errors.Wrap(err, "truncate")
}
return nil
}
func publicSSHKeyPath(d *drivers.BaseDriver) string {
return d.GetSSHKeyPath() + ".pub"
}
// Restart a host. This may just call Stop(); Start() if the provider does not
// have any special restart behaviour.
func Restart(d drivers.Driver) error {
if err := d.Stop(); err != nil {
return err
}
return d.Start()
}
// MakeDiskImage makes a boot2docker VM disk image.
func MakeDiskImage(d *drivers.BaseDriver, boot2dockerURL string, diskSize int) error {
glog.Infof("Making disk image using store path: %s", d.StorePath)
b2 := mcnutils.NewB2dUtils(d.StorePath)
if err := b2.CopyIsoToMachineDir(boot2dockerURL, d.MachineName); err != nil {
return errors.Wrap(err, "copy iso to machine dir")
}
keyPath := d.GetSSHKeyPath()
glog.Infof("Creating ssh key: %s...", keyPath)
if err := ssh.GenerateSSHKey(keyPath); err != nil {
return errors.Wrap(err, "generate ssh key")
}
diskPath := GetDiskPath(d)
glog.Infof("Creating raw disk image: %s...", diskPath)
if _, err := os.Stat(diskPath); os.IsNotExist(err) {
if err := createRawDiskImage(publicSSHKeyPath(d), diskPath, diskSize); err != nil {
return errors.Wrapf(err, "createRawDiskImage(%s)", diskPath)
}
machPath := d.ResolveStorePath(".")
if err := fixMachinePermissions(machPath); err != nil {
return errors.Wrapf(err, "fixing permissions on %s", machPath)
}
}
return nil
}
func fixMachinePermissions(path string) error {
glog.Infof("Fixing permissions on %s ...", path)
if err := os.Chown(path, syscall.Getuid(), syscall.Getegid()); err != nil {
return errors.Wrap(err, "chown dir")
}
files, err := ioutil.ReadDir(path)
if err != nil {
return errors.Wrap(err, "read dir")
}
for _, f := range files {
fp := filepath.Join(path, f.Name())
if err := os.Chown(fp, syscall.Getuid(), syscall.Getegid()); err != nil {
return errors.Wrap(err, "chown file")
}
}
return nil
}
......@@ -48,27 +48,3 @@ func Test_createDiskImage(t *testing.T) {
t.Errorf("Disk size is %v, want %v", fi.Size(), sizeInBytes)
}
}
func TestExtractVMDriverVersion(t *testing.T) {
v := extractVMDriverVersion("")
if len(v) != 0 {
t.Error("Expected empty string")
}
v = extractVMDriverVersion("random text")
if len(v) != 0 {
t.Error("Expected empty string")
}
expectedVersion := "1.2.3"
v = extractVMDriverVersion("version: v1.2.3")
if expectedVersion != v {
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
}
v = extractVMDriverVersion("version: 1.2.3")
if expectedVersion != v {
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
}
}
......@@ -30,14 +30,11 @@ import (
"k8s.io/apimachinery/pkg/util/net"
pkgdrivers "k8s.io/minikube/pkg/drivers"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/cruntime"
"k8s.io/minikube/pkg/minikube/vmpath"
"k8s.io/minikube/pkg/util/retry"
)
const driverName = constants.DriverNone
// cleanupPaths are paths to be removed by cleanup, and are used by both kubeadm and minikube.
var cleanupPaths = []string{
vmpath.GuestEphemeralDir,
......@@ -93,7 +90,7 @@ func (d *Driver) Create() error {
// DriverName returns the name of the driver
func (d *Driver) DriverName() string {
return driverName
return "none"
}
// GetIP returns an IP or hostname that this host is available at
......
......@@ -157,7 +157,7 @@ func copyConfigFiles() error {
if err := mcnutils.CopyFile(filepath.Join(nodeDir, containerdConfigTomlPath), filepath.Join(nodeDir, storedContainerdConfigTomlPath)); err != nil {
return errors.Wrap(err, "copying default config.toml")
}
log.Print("Copying containerd config.toml with gvisor...")
log.Printf("Copying %s asset to %s", constants.GvisorConfigTomlTargetName, filepath.Join(nodeDir, containerdConfigTomlPath))
if err := copyAssetToDest(constants.GvisorConfigTomlTargetName, filepath.Join(nodeDir, containerdConfigTomlPath)); err != nil {
return errors.Wrap(err, "copying gvisor version of config.toml")
}
......@@ -171,8 +171,13 @@ func copyAssetToDest(targetName, dest string) error {
asset = a
}
}
if asset == nil {
return fmt.Errorf("no asset matching target %s among %+v", targetName, assets.Addons["gvisor"])
}
// Now, copy the data from this asset to dest
src := filepath.Join(constants.GvisorFilesPath, asset.GetTargetName())
log.Printf("%s asset path: %s", targetName, src)
contents, err := ioutil.ReadFile(src)
if err != nil {
return errors.Wrapf(err, "getting contents of %s", asset.GetAssetName())
......@@ -182,6 +187,8 @@ func copyAssetToDest(targetName, dest string) error {
return errors.Wrapf(err, "removing %s", dest)
}
}
log.Printf("creating %s", dest)
f, err := os.Create(dest)
if err != nil {
return errors.Wrapf(err, "creating %s", dest)
......@@ -193,28 +200,24 @@ func copyAssetToDest(targetName, dest string) error {
}
func restartContainerd() error {
dir := filepath.Join(nodeDir, "usr/libexec/sudo")
if err := os.Setenv("LD_LIBRARY_PATH", dir); err != nil {
return errors.Wrap(err, dir)
}
log.Print("restartContainerd black magic happening")
log.Print("Stopping rpc-statd.service...")
// first, stop rpc-statd.service
cmd := exec.Command("sudo", "-E", "systemctl", "stop", "rpc-statd.service")
cmd := exec.Command("/usr/sbin/chroot", "/node", "sudo", "systemctl", "stop", "rpc-statd.service")
if out, err := cmd.CombinedOutput(); err != nil {
fmt.Println(string(out))
return errors.Wrap(err, "stopping rpc-statd.service")
}
// restart containerd
log.Print("Restarting containerd...")
cmd = exec.Command("sudo", "-E", "systemctl", "restart", "containerd")
cmd = exec.Command("/usr/sbin/chroot", "/node", "sudo", "systemctl", "restart", "containerd")
if out, err := cmd.CombinedOutput(); err != nil {
log.Print(string(out))
return errors.Wrap(err, "restarting containerd")
}
// start rpc-statd.service
log.Print("Starting rpc-statd...")
cmd = exec.Command("sudo", "-E", "systemctl", "start", "rpc-statd.service")
cmd = exec.Command("/usr/sbin/chroot", "/node", "sudo", "systemctl", "start", "rpc-statd.service")
if out, err := cmd.CombinedOutput(); err != nil {
log.Print(string(out))
return errors.Wrap(err, "restarting rpc-statd.service")
......
......@@ -66,7 +66,7 @@ Wants=crio.service
[Service]
ExecStart=
ExecStart=/var/lib/minikube/binaries/v1.16.1/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=remote --container-runtime-endpoint=/var/run/crio/crio.sock --fail-swap-on=false --hostname-override=minikube --image-service-endpoint=/var/run/crio/crio.sock --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-manifest-path=/etc/kubernetes/manifests --runtime-request-timeout=15m
ExecStart=/var/lib/minikube/binaries/v1.16.2/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=remote --container-runtime-endpoint=/var/run/crio/crio.sock --fail-swap-on=false --hostname-override=minikube --image-service-endpoint=/var/run/crio/crio.sock --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-manifest-path=/etc/kubernetes/manifests --runtime-request-timeout=15m
[Install]
`,
......@@ -84,7 +84,7 @@ Wants=containerd.service
[Service]
ExecStart=
ExecStart=/var/lib/minikube/binaries/v1.16.1/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock --fail-swap-on=false --hostname-override=minikube --image-service-endpoint=unix:///run/containerd/containerd.sock --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-manifest-path=/etc/kubernetes/manifests --runtime-request-timeout=15m
ExecStart=/var/lib/minikube/binaries/v1.16.2/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock --fail-swap-on=false --hostname-override=minikube --image-service-endpoint=unix:///run/containerd/containerd.sock --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-manifest-path=/etc/kubernetes/manifests --runtime-request-timeout=15m
[Install]
`,
......@@ -109,7 +109,7 @@ Wants=containerd.service
[Service]
ExecStart=
ExecStart=/var/lib/minikube/binaries/v1.16.1/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock --fail-swap-on=false --hostname-override=minikube --image-service-endpoint=unix:///run/containerd/containerd.sock --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.200 --pod-manifest-path=/etc/kubernetes/manifests --runtime-request-timeout=15m
ExecStart=/var/lib/minikube/binaries/v1.16.2/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock --fail-swap-on=false --hostname-override=minikube --image-service-endpoint=unix:///run/containerd/containerd.sock --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.200 --pod-manifest-path=/etc/kubernetes/manifests --runtime-request-timeout=15m
[Install]
`,
......@@ -128,7 +128,7 @@ Wants=docker.socket
[Service]
ExecStart=
ExecStart=/var/lib/minikube/binaries/v1.16.1/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=docker --fail-swap-on=false --hostname-override=minikube --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-infra-container-image=docker-proxy-image.io/google_containers/pause:3.1 --pod-manifest-path=/etc/kubernetes/manifests
ExecStart=/var/lib/minikube/binaries/v1.16.2/kubelet --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --container-runtime=docker --fail-swap-on=false --hostname-override=minikube --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-infra-container-image=docker-proxy-image.io/google_containers/pause:3.1 --pod-manifest-path=/etc/kubernetes/manifests
[Install]
`,
......
......@@ -43,8 +43,10 @@ import (
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
"github.com/spf13/viper"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/out"
......@@ -78,7 +80,7 @@ func init() {
// CacheISO downloads and caches ISO.
func CacheISO(config cfg.MachineConfig) error {
if localDriver(config.VMDriver) {
if driver.BareMetal(config.VMDriver) {
return nil
}
return config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO)
......@@ -136,14 +138,6 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error)
return h, nil
}
// localDriver returns whether or not the driver should be considered local
func localDriver(name string) bool {
if name == constants.DriverNone || name == constants.DriverMock {
return true
}
return false
}
// configureHost handles any post-powerup configuration required
func configureHost(h *host.Host, e *engine.Options) error {
start := time.Now()
......@@ -165,7 +159,7 @@ func configureHost(h *host.Host, e *engine.Options) error {
}
}
if localDriver(h.Driver.DriverName()) {
if driver.BareMetal(h.Driver.DriverName()) {
glog.Infof("%s is a local driver, skipping auth/time setup", h.Driver.DriverName())
return nil
}
......@@ -251,7 +245,7 @@ func StopHost(api libmachine.API) error {
}
out.T(out.Stopping, `Stopping "{{.profile_name}}" in {{.driver_name}} ...`, out.V{"profile_name": cfg.GetMachineName(), "driver_name": host.DriverName})
if host.DriverName == constants.DriverHyperv {
if host.DriverName == driver.HyperV {
glog.Infof("As there are issues with stopping Hyper-V VMs using API, trying to shut down using SSH")
if err := trySSHPowerOff(host); err != nil {
return errors.Wrap(err, "ssh power off")
......@@ -287,7 +281,7 @@ func DeleteHost(api libmachine.API) error {
}
// This is slow if SSH is not responding, but HyperV hangs otherwise, See issue #2914
if host.Driver.DriverName() == constants.DriverHyperv {
if host.Driver.DriverName() == driver.HyperV {
if err := trySSHPowerOff(host); err != nil {
glog.Infof("Unable to power off minikube because the host was not found.")
}
......@@ -424,13 +418,13 @@ func showRemoteOsRelease(driver drivers.Driver) {
}
func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) {
if config.VMDriver == constants.DriverVmwareFusion && viper.GetBool(cfg.ShowDriverDeprecationNotification) {
if config.VMDriver == driver.VMwareFusion && viper.GetBool(cfg.ShowDriverDeprecationNotification) {
out.WarningT(`The vmwarefusion driver is deprecated and support for it will be removed in a future release.
Please consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver.
See https://minikube.sigs.k8s.io/docs/reference/drivers/vmware/ for more information.
To disable this message, run [minikube config set ShowDriverDeprecationNotification false]`)
}
if !localDriver(config.VMDriver) {
if !driver.BareMetal(config.VMDriver) {
out.T(out.StartingVM, "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...", out.V{"driver_name": config.VMDriver, "number_of_cpus": config.CPUs, "memory_size": config.Memory, "disk_size": config.DiskSize})
} else {
info, err := getHostInfo()
......@@ -439,16 +433,12 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error
}
}
def, err := registry.Driver(config.VMDriver)
if err != nil {
if err == registry.ErrDriverNotFound {
return nil, fmt.Errorf("unsupported driver: %s", config.VMDriver)
}
return nil, errors.Wrap(err, "error getting driver")
def := registry.Driver(config.VMDriver)
if def.Empty() {
return nil, fmt.Errorf("unsupported/missing driver: %s", config.VMDriver)
}
driver := def.ConfigCreator(config)
data, err := json.Marshal(driver)
dd := def.Config(config)
data, err := json.Marshal(dd)
if err != nil {
return nil, errors.Wrap(err, "marshal")
}
......@@ -468,7 +458,7 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error
return nil, errors.Wrap(err, "create")
}
if !localDriver(config.VMDriver) {
if !driver.BareMetal(config.VMDriver) {
showRemoteOsRelease(h.Driver)
// Ensure that even new VM's have proper time synchronization up front
// It's 2019, and I can't believe I am still dealing with time desync as a problem.
......@@ -510,9 +500,9 @@ func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
// GetVMHostIP gets the ip address to be used for mapping host -> VM and VM -> host
func GetVMHostIP(host *host.Host) (net.IP, error) {
switch host.DriverName {
case constants.DriverKvm2:
case driver.KVM2:
return net.ParseIP("192.168.39.1"), nil
case constants.DriverHyperv:
case driver.HyperV:
re := regexp.MustCompile(`"VSwitch": "(.*?)",`)
// TODO(aprindle) Change this to deserialize the driver instead
hypervVirtualSwitch := re.FindStringSubmatch(string(host.RawDriver))[1]
......@@ -521,8 +511,8 @@ func GetVMHostIP(host *host.Host) (net.IP, error) {
return []byte{}, errors.Wrap(err, fmt.Sprintf("ip for interface (%s)", hypervVirtualSwitch))
}
return ip, nil
case constants.DriverVirtualbox:
out, err := exec.Command(detectVBoxManageCmd(), "showvminfo", host.Name, "--machinereadable").Output()
case driver.VirtualBox:
out, err := exec.Command(driver.VBoxManagePath(), "showvminfo", host.Name, "--machinereadable").Output()
if err != nil {
return []byte{}, errors.Wrap(err, "vboxmanage")
}
......@@ -533,9 +523,9 @@ func GetVMHostIP(host *host.Host) (net.IP, error) {
return []byte{}, errors.Wrap(err, "Error getting VM/Host IP address")
}
return ip, nil
case constants.DriverHyperkit:
case driver.HyperKit:
return net.ParseIP("192.168.64.1"), nil
case constants.DriverVmware:
case driver.VMware:
vmIPString, err := host.Driver.GetIP()
if err != nil {
return []byte{}, errors.Wrap(err, "Error getting VM IP address")
......
......@@ -22,12 +22,16 @@ import (
"testing"
"time"
// Driver used by testdata
_ "k8s.io/minikube/pkg/minikube/registry/drvs/virtualbox"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/provision"
"github.com/docker/machine/libmachine/state"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/registry"
"k8s.io/minikube/pkg/minikube/tests"
)
......@@ -43,18 +47,13 @@ func createMockDriverHost(c config.MachineConfig) interface{} {
func RegisterMockDriver(t *testing.T) {
t.Helper()
_, err := registry.Driver(constants.DriverMock)
// Already registered
if err == nil {
if !registry.Driver(driver.Mock).Empty() {
return
}
err = registry.Register(registry.DriverDef{
Name: constants.DriverMock,
Builtin: true,
ConfigCreator: createMockDriverHost,
DriverCreator: func() drivers.Driver {
return &tests.MockDriver{T: t}
},
err := registry.Register(registry.DriverDef{
Name: driver.Mock,
Config: createMockDriverHost,
Init: func() drivers.Driver { return &tests.MockDriver{T: t} },
})
if err != nil {
t.Fatalf("register failed: %v", err)
......@@ -62,7 +61,7 @@ func RegisterMockDriver(t *testing.T) {
}
var defaultMachineConfig = config.MachineConfig{
VMDriver: constants.DriverMock,
VMDriver: driver.Mock,
MinikubeISO: constants.DefaultISOURL,
Downloader: MockDownloader{},
DockerEnv: []string{"MOCK_MAKE_IT_PROVISION=true"},
......@@ -99,7 +98,7 @@ func TestCreateHost(t *testing.T) {
}
found := false
for _, def := range registry.ListDrivers() {
for _, def := range registry.List() {
if h.DriverName == def.Name {
found = true
break
......@@ -107,7 +106,7 @@ func TestCreateHost(t *testing.T) {
}
if !found {
t.Fatalf("Wrong driver name: %v. It should be among drivers %v", h.DriverName, registry.ListDrivers())
t.Fatalf("Wrong driver name: %v. It should be among drivers %v", h.DriverName, registry.List())
}
}
......@@ -216,7 +215,7 @@ func TestStartHostConfig(t *testing.T) {
provision.SetDetector(md)
config := config.MachineConfig{
VMDriver: constants.DriverMock,
VMDriver: driver.Mock,
DockerEnv: []string{"FOO=BAR"},
DockerOpt: []string{"param=value"},
Downloader: MockDownloader{},
......
......@@ -21,6 +21,7 @@ import (
"path/filepath"
"github.com/docker/machine/libmachine/host"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
......@@ -69,6 +70,7 @@ func ListMachines(miniHome ...string) (validMachines []*Machine, inValidMachines
for _, n := range pDirs {
p, err := LoadMachine(n)
if err != nil {
glog.Infof("%s not valid: %v", n, err)
inValidMachines = append(inValidMachines, p)
continue
}
......
......@@ -22,8 +22,6 @@ import (
"os"
"reflect"
"testing"
"k8s.io/minikube/pkg/minikube/constants"
)
type configTestCase struct {
......@@ -48,10 +46,10 @@ var configTestCases = []configTestCase{
"log_dir": "/etc/hosts",
"show-libmachine-logs": true,
"v": 5,
"vm-driver": "kvm2"
"vm-driver": "test-driver"
}`,
config: map[string]interface{}{
"vm-driver": constants.DriverKvm2,
"vm-driver": "test-driver",
"cpus": 4,
"disk-size": "20g",
"v": 5,
......@@ -132,7 +130,7 @@ func TestReadConfig(t *testing.T) {
}
expectedConfig := map[string]interface{}{
"vm-driver": constants.DriverKvm2,
"vm-driver": "test-driver",
"cpus": 4,
"disk-size": "20g",
"show-libmachine-logs": true,
......@@ -151,7 +149,7 @@ func TestWriteConfig(t *testing.T) {
}
cfg := map[string]interface{}{
"vm-driver": constants.DriverKvm2,
"vm-driver": "test-driver",
"cpus": 4,
"disk-size": "20g",
"show-libmachine-logs": true,
......
......@@ -44,7 +44,7 @@ func (p *Profile) IsValid() bool {
return true
}
// check if the profile is an internal keywords
// ProfileNameInReservedKeywords checks if the profile is an internal keywords
func ProfileNameInReservedKeywords(name string) bool {
for _, v := range keywords {
if strings.EqualFold(v, name) {
......
......@@ -35,33 +35,6 @@ const (
ClusterDNSDomain = "cluster.local"
)
// DriverMock is a mock driver.
const DriverMock = "mock-driver"
// DriverNone is the none driver.
const DriverNone = "none"
// DriverKvm2 is the kvm2 driver option name for in linux
const DriverKvm2 = "kvm2"
// DriverVirtualbox is the virtualbox driver option name
const DriverVirtualbox = "virtualbox"
// DriverHyperkit is the hyperkit driver option name for mac os
const DriverHyperkit = "hyperkit"
// DriverVmware is the vmware driver option name
const DriverVmware = "vmware"
// DriverVmwareFusion is the vmware fusion driver option
const DriverVmwareFusion = "vmwarefusion"
// DriverHyperv is the hyperv driver option for windows
const DriverHyperv = "hyperv"
// DriverParallels is the parallels driver option name
const DriverParallels = "parallels"
// DefaultMinipath is the default Minikube path (under the home directory)
var DefaultMinipath = filepath.Join(homedir.HomeDir(), ".minikube")
......@@ -92,10 +65,10 @@ var DefaultISOURL = fmt.Sprintf("https://storage.googleapis.com/%s/minikube-%s.i
var DefaultISOSHAURL = DefaultISOURL + SHASuffix
// DefaultKubernetesVersion is the default kubernetes version
var DefaultKubernetesVersion = "v1.16.1"
var DefaultKubernetesVersion = "v1.16.2"
// NewestKubernetesVersion is the newest Kubernetes version to test against
var NewestKubernetesVersion = "v1.16.1"
var NewestKubernetesVersion = "v1.16.2"
// OldestKubernetesVersion is the oldest Kubernetes version to test against
var OldestKubernetesVersion = "v1.11.10"
......
......@@ -20,12 +20,3 @@ package constants
// DefaultMountDir is the default mounting directory for Darwin
var DefaultMountDir = "/Users"
// SupportedVMDrivers is a list of supported drivers on Darwin.
var SupportedVMDrivers = [...]string{
DriverVirtualbox,
DriverParallels,
DriverVmwareFusion,
DriverHyperkit,
DriverVmware,
}
......@@ -19,15 +19,3 @@ limitations under the License.
package constants
var DefaultMountDir = "$HOME"
// SupportedVMDrivers is a list of supported drivers on all platforms.
var SupportedVMDrivers = [...]string{
DriverVirtualbox,
DriverParallels,
DriverVmwareFusion,
DriverHyperv,
DriverHyperkit,
DriverKvm2,
DriverVmware,
DriverNone,
}
......@@ -24,13 +24,3 @@ import (
// DefaultMountDir is the default mount dir
var DefaultMountDir = homedir.HomeDir()
// SupportedVMDrivers is a list of supported drivers on Linux.
var SupportedVMDrivers = [...]string{
DriverVirtualbox,
DriverParallels,
DriverVmwareFusion,
DriverKvm2,
DriverVmware,
DriverNone,
}
......@@ -23,11 +23,3 @@ import (
)
var DefaultMountDir = homedir.HomeDir()
// SupportedVMDrivers is a list of supported drivers on Windows.
var SupportedVMDrivers = [...]string{
DriverVirtualbox,
DriverVmwareFusion,
DriverHyperv,
DriverVmware,
}
/*
Copyright 2019 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 driver
import (
"fmt"
"os"
"sort"
"github.com/golang/glog"
"k8s.io/minikube/pkg/minikube/registry"
)
const (
Mock = "mock"
None = "none"
KVM2 = "kvm2"
VirtualBox = "virtualbox"
HyperKit = "hyperkit"
VMware = "vmware"
VMwareFusion = "vmwarefusion"
HyperV = "hyperv"
Parallels = "parallels"
)
var (
// systemdResolvConf is path to systemd's DNS configuration. https://github.com/kubernetes/minikube/issues/3511
systemdResolvConf = "/run/systemd/resolve/resolv.conf"
)
// SupportedDrivers returns a list of supported drivers
func SupportedDrivers() []string {
return supportedDrivers
}
// Supported returns if the driver is supported on this host.
func Supported(name string) bool {
for _, d := range supportedDrivers {
if name == d {
return true
}
}
return false
}
// BareMetal returns if this driver is unisolated
func BareMetal(name string) bool {
return name == None || name == Mock
}
// FlagHints are hints for what default options should be used for this driver
type FlagHints struct {
ExtraOptions string
CacheImages bool
}
// FlagDefaults returns suggested defaults based on a driver
func FlagDefaults(name string) FlagHints {
if name != None {
return FlagHints{CacheImages: true}
}
extraOpts := ""
if _, err := os.Stat(systemdResolvConf); err == nil {
extraOpts = fmt.Sprintf("kubelet.resolv-conf=%s", systemdResolvConf)
}
return FlagHints{
ExtraOptions: extraOpts,
CacheImages: false,
}
}
// Choices returns a list of drivers which are possible on this system
func Choices() []registry.DriverState {
options := []registry.DriverState{}
for _, ds := range registry.Installed() {
if !ds.State.Healthy {
glog.Warningf("%q is installed, but unhealthy: %v", ds.Name, ds.State.Error)
continue
}
options = append(options, ds)
}
// Descending priority for predictability and appearance
sort.Slice(options, func(i, j int) bool {
return options[i].Priority > options[j].Priority
})
return options
}
// Choose returns a suggested driver from a set of options
func Choose(options []registry.DriverState) (registry.DriverState, []registry.DriverState) {
pick := registry.DriverState{}
for _, ds := range options {
if ds.Priority <= registry.Discouraged {
glog.Infof("not recommending %q due to priority: %d", ds.Name, ds.Priority)
continue
}
if ds.Priority > pick.Priority {
glog.V(1).Infof("%q has a higher priority (%d) than %q (%d)", ds.Name, ds.Priority, pick.Name, pick.Priority)
pick = ds
}
}
alternates := []registry.DriverState{}
for _, ds := range options {
if ds != pick {
alternates = append(alternates, ds)
}
}
glog.Infof("Picked: %+v", pick)
glog.Infof("Alternatives: %+v", alternates)
return pick, alternates
}
// Status returns the status of a driver
func Status(name string) registry.State {
return registry.Status(name)
}
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Copyright 2019 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.
......@@ -14,13 +14,20 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package driver
import (
"os/exec"
)
import "os/exec"
func detectVBoxManageCmd() string {
// supportedDrivers is a list of supported drivers on Darwin.
var supportedDrivers = []string{
VirtualBox,
Parallels,
VMwareFusion,
HyperKit,
VMware,
}
func VBoxManagePath() string {
cmd := "VBoxManage"
if path, err := exec.LookPath(cmd); err == nil {
return path
......
......@@ -14,13 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package driver
import (
"os/exec"
)
func detectVBoxManageCmd() string {
// supportedDrivers is a list of supported drivers on Linux.
var supportedDrivers = []string{
VirtualBox,
Parallels,
VMwareFusion,
KVM2,
VMware,
None,
}
func VBoxManagePath() string {
cmd := "VBoxManage"
if path, err := exec.LookPath(cmd); err == nil {
return path
......
/*
Copyright 2018 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 driver
import (
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/minikube/pkg/minikube/registry"
)
func TestSupportedDrivers(t *testing.T) {
got := SupportedDrivers()
found := false
for _, s := range SupportedDrivers() {
if s == VirtualBox {
found = true
}
}
if found == false {
t.Errorf("%s not in supported drivers: %v", VirtualBox, got)
}
}
func TestSupported(t *testing.T) {
if !Supported(VirtualBox) {
t.Errorf("Supported(%s) is false", VirtualBox)
}
if Supported("yabba?") {
t.Errorf("Supported(yabba?) is true")
}
}
func TestBareMetal(t *testing.T) {
if !BareMetal(None) {
t.Errorf("Supported(%s) is false", None)
}
if BareMetal(VirtualBox) {
t.Errorf("Supported(%s) is true", VirtualBox)
}
}
func TestFlagDefaults(t *testing.T) {
expected := FlagHints{CacheImages: true}
if diff := cmp.Diff(FlagDefaults(VirtualBox), expected); diff != "" {
t.Errorf("defaults mismatch (-want +got):\n%s", diff)
}
tf, err := ioutil.TempFile("", "resolv.conf")
if err != nil {
t.Fatalf("tempfile: %v", err)
}
defer os.Remove(tf.Name()) // clean up
expected = FlagHints{
CacheImages: false,
ExtraOptions: fmt.Sprintf("kubelet.resolv-conf=%s", tf.Name()),
}
systemdResolvConf = tf.Name()
if diff := cmp.Diff(FlagDefaults(None), expected); diff != "" {
t.Errorf("defaults mismatch (-want +got):\n%s", diff)
}
}
func TestChoices(t *testing.T) {
tests := []struct {
def registry.DriverDef
choices []string
pick string
alts []string
}{
{
def: registry.DriverDef{
Name: "unhealthy",
Priority: registry.Default,
Status: func() registry.State { return registry.State{Installed: true, Healthy: false} },
},
choices: []string{},
pick: "",
alts: []string{},
},
{
def: registry.DriverDef{
Name: "discouraged",
Priority: registry.Discouraged,
Status: func() registry.State { return registry.State{Installed: true, Healthy: true} },
},
choices: []string{"discouraged"},
pick: "",
alts: []string{"discouraged"},
},
{
def: registry.DriverDef{
Name: "default",
Priority: registry.Default,
Status: func() registry.State { return registry.State{Installed: true, Healthy: true} },
},
choices: []string{"default", "discouraged"},
pick: "default",
alts: []string{"discouraged"},
},
{
def: registry.DriverDef{
Name: "preferred",
Priority: registry.Preferred,
Status: func() registry.State { return registry.State{Installed: true, Healthy: true} },
},
choices: []string{"preferred", "default", "discouraged"},
pick: "preferred",
alts: []string{"default", "discouraged"},
},
}
for _, tc := range tests {
t.Run(tc.def.Name, func(t *testing.T) {
if err := registry.Register(tc.def); err != nil {
t.Errorf("register returned error: %v", err)
}
got := Choices()
gotNames := []string{}
for _, c := range got {
gotNames = append(gotNames, c.Name)
}
if diff := cmp.Diff(gotNames, tc.choices); diff != "" {
t.Errorf("choices mismatch (-want +got):\n%s", diff)
}
pick, alts := Choose(got)
if pick.Name != tc.pick {
t.Errorf("pick = %q, expected %q", pick.Name, tc.pick)
}
gotAlts := []string{}
for _, a := range alts {
gotAlts = append(gotAlts, a.Name)
}
if diff := cmp.Diff(gotAlts, tc.alts); diff != "" {
t.Errorf("alts mismatch (-want +got):\n%s", diff)
}
})
}
}
......@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package driver
import (
"fmt"
......@@ -27,7 +27,15 @@ import (
"golang.org/x/sys/windows/registry"
)
func detectVBoxManageCmd() string {
// supportedDrivers is a list of supported drivers on Windows.
var supportedDrivers = []string{
VirtualBox,
VMwareFusion,
HyperV,
VMware,
}
func VBoxManagePath() string {
cmd := "VBoxManage"
if p := os.Getenv("VBOX_INSTALL_PATH"); p != "" {
if path, err := exec.LookPath(filepath.Join(p, cmd)); err == nil {
......
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Copyright 2019 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.
......@@ -14,147 +14,32 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package drivers
package driver
import (
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"syscall"
"github.com/blang/semver"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/mcnflag"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/golang/glog"
"github.com/hashicorp/go-getter"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/version"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/util"
)
// GetDiskPath returns the path of the machine disk image
func GetDiskPath(d *drivers.BaseDriver) string {
return filepath.Join(d.ResolveStorePath("."), d.GetMachineName()+".rawdisk")
}
// CommonDriver is the common driver base class
type CommonDriver struct{}
// GetCreateFlags is not implemented yet
func (d *CommonDriver) GetCreateFlags() []mcnflag.Flag {
return nil
}
// SetConfigFromFlags is not implemented yet
func (d *CommonDriver) SetConfigFromFlags(flags drivers.DriverOptions) error {
return nil
}
func createRawDiskImage(sshKeyPath, diskPath string, diskSizeMb int) error {
tarBuf, err := mcnutils.MakeDiskImage(sshKeyPath)
if err != nil {
return errors.Wrap(err, "make disk image")
}
file, err := os.OpenFile(diskPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
if err != nil {
return errors.Wrap(err, "open")
}
defer file.Close()
if _, err := file.Seek(0, io.SeekStart); err != nil {
return errors.Wrap(err, "seek")
}
if _, err := file.Write(tarBuf.Bytes()); err != nil {
return errors.Wrap(err, "write tar")
}
if err := file.Close(); err != nil {
return errors.Wrapf(err, "closing file %s", diskPath)
}
if err := os.Truncate(diskPath, int64(diskSizeMb*1000000)); err != nil {
return errors.Wrap(err, "truncate")
}
return nil
}
func publicSSHKeyPath(d *drivers.BaseDriver) string {
return d.GetSSHKeyPath() + ".pub"
}
// Restart a host. This may just call Stop(); Start() if the provider does not
// have any special restart behaviour.
func Restart(d drivers.Driver) error {
if err := d.Stop(); err != nil {
return err
}
return d.Start()
}
// MakeDiskImage makes a boot2docker VM disk image.
func MakeDiskImage(d *drivers.BaseDriver, boot2dockerURL string, diskSize int) error {
glog.Infof("Making disk image using store path: %s", d.StorePath)
b2 := mcnutils.NewB2dUtils(d.StorePath)
if err := b2.CopyIsoToMachineDir(boot2dockerURL, d.MachineName); err != nil {
return errors.Wrap(err, "copy iso to machine dir")
}
keyPath := d.GetSSHKeyPath()
glog.Infof("Creating ssh key: %s...", keyPath)
if err := ssh.GenerateSSHKey(keyPath); err != nil {
return errors.Wrap(err, "generate ssh key")
}
diskPath := GetDiskPath(d)
glog.Infof("Creating raw disk image: %s...", diskPath)
if _, err := os.Stat(diskPath); os.IsNotExist(err) {
if err := createRawDiskImage(publicSSHKeyPath(d), diskPath, diskSize); err != nil {
return errors.Wrapf(err, "createRawDiskImage(%s)", diskPath)
}
machPath := d.ResolveStorePath(".")
if err := fixMachinePermissions(machPath); err != nil {
return errors.Wrapf(err, "fixing permissions on %s", machPath)
}
}
return nil
}
func fixMachinePermissions(path string) error {
glog.Infof("Fixing permissions on %s ...", path)
if err := os.Chown(path, syscall.Getuid(), syscall.Getegid()); err != nil {
return errors.Wrap(err, "chown dir")
}
files, err := ioutil.ReadDir(path)
if err != nil {
return errors.Wrap(err, "read dir")
}
for _, f := range files {
fp := filepath.Join(path, f.Name())
if err := os.Chown(fp, syscall.Getuid(), syscall.Getegid()); err != nil {
return errors.Wrap(err, "chown file")
}
}
return nil
}
// InstallOrUpdate downloads driver if it is not present, or updates it if there's a newer version
func InstallOrUpdate(driver string, directory string, v semver.Version, interactive bool, autoUpdate bool) error {
if driver != constants.DriverKvm2 && driver != constants.DriverHyperkit {
func InstallOrUpdate(name string, directory string, v semver.Version, interactive bool, autoUpdate bool) error {
if name != KVM2 && name != HyperKit {
return nil
}
executable := fmt.Sprintf("docker-machine-driver-%s", driver)
executable := fmt.Sprintf("docker-machine-driver-%s", name)
exists := driverExists(executable)
path, err := validateDriver(executable, v)
if !exists || (err != nil && autoUpdate) {
......@@ -165,13 +50,12 @@ func InstallOrUpdate(driver string, directory string, v semver.Version, interact
return derr
}
}
return fixDriverPermissions(driver, path, interactive)
return fixDriverPermissions(name, path, interactive)
}
// fixDriverPermissions fixes the permissions on a driver
func fixDriverPermissions(driver string, path string, interactive bool) error {
// This method only supports hyperkit so far (because it's complicated)
if driver != constants.DriverHyperkit {
func fixDriverPermissions(name string, path string, interactive bool) error {
if name != HyperKit {
return nil
}
......@@ -193,7 +77,7 @@ func fixDriverPermissions(driver string, path string, interactive bool) error {
example.WriteString(fmt.Sprintf(" $ %s \n", strings.Join(c.Args, " ")))
}
out.T(out.Permissions, "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\n\n{{ .example }}\n", out.V{"driver": driver, "example": example.String()})
out.T(out.Permissions, "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\n\n{{ .example }}\n", out.V{"driver": name, "example": example.String()})
for _, c := range cmds {
testArgs := append([]string{"-n"}, c.Args[1:]...)
test := exec.Command("sudo", testArgs...)
......@@ -214,9 +98,9 @@ func fixDriverPermissions(driver string, path string, interactive bool) error {
}
// validateDriver validates if a driver appears to be up-to-date and installed properly
func validateDriver(driver string, v semver.Version) (string, error) {
glog.Infof("Validating %s, PATH=%s", driver, os.Getenv("PATH"))
path, err := exec.LookPath(driver)
func validateDriver(executable string, v semver.Version) (string, error) {
glog.Infof("Validating %s, PATH=%s", executable, os.Getenv("PATH"))
path, err := exec.LookPath(executable)
if err != nil {
return path, err
}
......@@ -228,7 +112,7 @@ func validateDriver(driver string, v semver.Version) (string, error) {
ev := extractVMDriverVersion(string(output))
if len(ev) == 0 {
return path, fmt.Errorf("%s: unable to extract version from %q", driver, output)
return path, fmt.Errorf("%s: unable to extract version from %q", executable, output)
}
vmDriverVersion, err := semver.Make(ev)
......@@ -236,26 +120,21 @@ func validateDriver(driver string, v semver.Version) (string, error) {
return path, errors.Wrap(err, "can't parse driver version")
}
if vmDriverVersion.LT(v) {
return path, fmt.Errorf("%s is version %s, want %s", driver, vmDriverVersion, v)
return path, fmt.Errorf("%s is version %s, want %s", executable, vmDriverVersion, v)
}
return path, nil
}
func driverExists(driver string) bool {
_, err := exec.LookPath(driver)
return err == nil
}
func driverWithChecksumURL(driver string, v semver.Version) string {
base := fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/v%s/%s", v, driver)
func driverWithChecksumURL(name string, v semver.Version) string {
base := fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/v%s/%s", v, name)
return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base)
}
// download an arbitrary driver
func download(driver string, destination string, v semver.Version) error {
out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": driver})
func download(name string, destination string, v semver.Version) error {
out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": name})
os.Remove(destination)
url := driverWithChecksumURL(driver, v)
url := driverWithChecksumURL(name, v)
client := &getter.Client{
Src: url,
Dst: destination,
......@@ -285,5 +164,10 @@ func extractVMDriverVersion(s string) string {
}
v := strings.TrimSpace(matches[1])
return strings.TrimPrefix(v, version.VersionPrefix)
return strings.TrimPrefix(v, "v")
}
func driverExists(driver string) bool {
_, err := exec.LookPath(driver)
return err == nil
}
/*
Copyright 2019 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 driver
import (
"testing"
)
func TestExtractVMDriverVersion(t *testing.T) {
v := extractVMDriverVersion("")
if len(v) != 0 {
t.Error("Expected empty string")
}
v = extractVMDriverVersion("random text")
if len(v) != 0 {
t.Error("Expected empty string")
}
expectedVersion := "1.2.3"
v = extractVMDriverVersion("version: v1.2.3")
if expectedVersion != v {
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
}
v = extractVMDriverVersion("version: 1.2.3")
if expectedVersion != v {
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
}
}
/*
Copyright 2018 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 virtualbox
......@@ -19,6 +19,7 @@ package machine
import (
"crypto/tls"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
......@@ -41,7 +42,7 @@ import (
"github.com/docker/machine/libmachine/version"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/out"
......@@ -80,27 +81,25 @@ type LocalClient struct {
}
// NewHost creates a new Host
func (api *LocalClient) NewHost(driverName string, rawDriver []byte) (*host.Host, error) {
var def registry.DriverDef
var err error
if def, err = registry.Driver(driverName); err != nil {
return nil, err
} else if !def.Builtin || def.DriverCreator == nil {
return api.legacyClient.NewHost(driverName, rawDriver)
func (api *LocalClient) NewHost(drvName string, rawDriver []byte) (*host.Host, error) {
def := registry.Driver(drvName)
if def.Empty() {
return nil, fmt.Errorf("driver %q does not exist", drvName)
}
driver := def.DriverCreator()
err = json.Unmarshal(rawDriver, driver)
if def.Init == nil {
return api.legacyClient.NewHost(drvName, rawDriver)
}
d := def.Init()
err := json.Unmarshal(rawDriver, d)
if err != nil {
return nil, errors.Wrapf(err, "Error getting driver %s", string(rawDriver))
}
return &host.Host{
ConfigVersion: version.ConfigVersion,
Name: driver.GetMachineName(),
Driver: driver,
DriverName: driver.DriverName(),
Name: d.GetMachineName(),
Driver: d,
DriverName: d.DriverName(),
HostOptions: &host.Options{
AuthOptions: &auth.Options{
CertDir: api.certsDir,
......@@ -127,14 +126,14 @@ func (api *LocalClient) Load(name string) (*host.Host, error) {
return nil, errors.Wrapf(err, "filestore %q", name)
}
var def registry.DriverDef
if def, err = registry.Driver(h.DriverName); err != nil {
return nil, err
} else if !def.Builtin || def.DriverCreator == nil {
def := registry.Driver(h.DriverName)
if def.Empty() {
return nil, fmt.Errorf("driver %q does not exist", h.DriverName)
}
if def.Init == nil {
return api.legacyClient.Load(name)
}
h.Driver = def.DriverCreator()
h.Driver = def.Init()
return h, json.Unmarshal(h.RawDriver, h.Driver)
}
......@@ -148,10 +147,10 @@ func (api *LocalClient) Close() error {
// CommandRunner returns best available command runner for this host
func CommandRunner(h *host.Host) (command.Runner, error) {
if h.DriverName == constants.DriverMock {
if h.DriverName == driver.Mock {
return &command.FakeCommandRunner{}, nil
}
if h.DriverName == constants.DriverNone {
if driver.BareMetal(h.Driver.DriverName()) {
return &command.ExecRunner{}, nil
}
client, err := sshutil.NewSSHClient(h.Driver)
......@@ -163,9 +162,11 @@ func CommandRunner(h *host.Host) (command.Runner, error) {
// Create creates the host
func (api *LocalClient) Create(h *host.Host) error {
if def, err := registry.Driver(h.DriverName); err != nil {
return err
} else if !def.Builtin || def.DriverCreator == nil {
def := registry.Driver(h.DriverName)
if def.Empty() {
return fmt.Errorf("driver %q does not exist", h.DriverName)
}
if def.Init == nil {
return api.legacyClient.Create(h)
}
......@@ -194,7 +195,7 @@ func (api *LocalClient) Create(h *host.Host) error {
{
"waiting",
func() error {
if h.Driver.DriverName() == constants.DriverNone {
if driver.BareMetal(h.Driver.DriverName()) {
return nil
}
return mcnutils.WaitFor(drivers.MachineInState(h.Driver, state.Running))
......@@ -203,7 +204,7 @@ func (api *LocalClient) Create(h *host.Host) error {
{
"provisioning",
func() error {
if h.Driver.DriverName() == constants.DriverNone {
if driver.BareMetal(h.Driver.DriverName()) {
return nil
}
pv := provision.NewBuildrootProvisioner(h.Driver)
......@@ -270,13 +271,10 @@ func (cg *CertGenerator) ValidateCertificate(addr string, authOptions *auth.Opti
return true, nil
}
func registerDriver(driverName string) {
def, err := registry.Driver(driverName)
if err != nil {
if err == registry.ErrDriverNotFound {
exit.UsageT("unsupported driver: {{.name}}", out.V{"name": driverName})
}
exit.WithError("error getting driver", err)
func registerDriver(drvName string) {
def := registry.Driver(drvName)
if def.Empty() {
exit.UsageT("unsupported or missing driver: {{.name}}", out.V{"name": drvName})
}
plugin.RegisterDriver(def.DriverCreator())
plugin.RegisterDriver(def.Init())
}
......@@ -27,9 +27,10 @@ import (
"testing"
"github.com/docker/machine/libmachine/drivers/plugin/localbinary"
"k8s.io/minikube/pkg/minikube/constants"
_ "k8s.io/minikube/pkg/minikube/drivers/virtualbox"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/virtualbox"
)
const vboxConfig = `
......@@ -77,12 +78,12 @@ func TestLocalClientNewHost(t *testing.T) {
}{
{
description: "host vbox correct",
driver: constants.DriverVirtualbox,
driver: driver.VirtualBox,
rawDriver: []byte(vboxConfig),
},
{
description: "host vbox incorrect",
driver: constants.DriverVirtualbox,
driver: driver.VirtualBox,
rawDriver: []byte("?"),
err: true,
},
......@@ -138,7 +139,7 @@ func TestRunDriver(t *testing.T) {
defer os.RemoveAll(tempDir)
os.Setenv(localbinary.PluginEnvKey, localbinary.PluginEnvVal)
os.Setenv(localbinary.PluginEnvDriverName, constants.DriverVirtualbox)
os.Setenv(localbinary.PluginEnvDriverName, driver.VirtualBox)
// Capture stdout and reset it later.
old := os.Stdout
......
......@@ -81,6 +81,7 @@ var styles = map[StyleEnum]style{
Check: {Prefix: "✅ "},
Celebration: {Prefix: "🎉 "},
Workaround: {Prefix: "👉 ", LowPrefix: lowIndent},
Sparkle: {Prefix: "✨ "},
// Specialized purpose styles
ISODownload: {Prefix: "💿 "},
......
......@@ -83,4 +83,5 @@ const (
Fileserver
Empty
Workaround
Sparkle
)
......@@ -20,30 +20,38 @@ package hyperkit
import (
"fmt"
"os/exec"
"strings"
"github.com/docker/machine/libmachine/drivers"
"github.com/pborman/uuid"
"k8s.io/minikube/pkg/drivers/hyperkit"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
const (
docURL = "https://minikube.sigs.k8s.io/docs/reference/drivers/hyperkit/"
)
func init() {
if err := registry.Register(registry.DriverDef{
Name: constants.DriverHyperkit,
Builtin: false,
ConfigCreator: createHyperkitHost,
Name: driver.HyperKit,
Config: configure,
Status: status,
Priority: registry.Preferred,
}); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
}
func createHyperkitHost(config cfg.MachineConfig) interface{} {
uuID := config.UUID
if uuID == "" {
uuID = uuid.NewUUID().String()
func configure(config cfg.MachineConfig) interface{} {
u := config.UUID
if u == "" {
u = uuid.NewUUID().String()
}
return &hyperkit.Driver{
......@@ -58,9 +66,24 @@ func createHyperkitHost(config cfg.MachineConfig) interface{} {
CPU: config.CPUs,
NFSShares: config.NFSShare,
NFSSharesRoot: config.NFSSharesRoot,
UUID: uuID,
UUID: u,
VpnKitSock: config.HyperkitVpnKitSock,
VSockPorts: config.HyperkitVSockPorts,
Cmdline: "loglevel=3 console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 systemd.legacy_systemd_cgroup_controller=yes random.trust_cpu=on hw_rng_model=virtio base host=" + cfg.GetMachineName(),
}
}
func status() registry.State {
path, err := exec.LookPath("hyperkit")
if err != nil {
return registry.State{Error: err, Fix: "Run 'brew install hyperkit'", Doc: docURL}
}
cmd := exec.Command(path, "-v")
out, err := cmd.CombinedOutput()
if err != nil {
return registry.State{Installed: true, Error: fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), out), Fix: "Run 'brew install hyperkit'", Doc: docURL}
}
return registry.State{Installed: true, Healthy: true}
}
......@@ -19,28 +19,37 @@ limitations under the License.
package hyperv
import (
"fmt"
"os/exec"
"strings"
"github.com/docker/machine/drivers/hyperv"
"github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
const (
docURL = "https://minikube.sigs.k8s.io/docs/reference/drivers/hyperv/"
)
func init() {
_ = registry.Register(registry.DriverDef{
Name: constants.DriverHyperv,
Builtin: true,
ConfigCreator: createHypervHost,
DriverCreator: func() drivers.Driver {
return hyperv.NewDriver("", "")
},
})
if err := registry.Register(registry.DriverDef{
Name: driver.HyperV,
Init: func() drivers.Driver { return hyperv.NewDriver("", "") },
Config: configure,
Status: status,
Priority: registry.Preferred,
}); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
}
func createHypervHost(config cfg.MachineConfig) interface{} {
func configure(config cfg.MachineConfig) interface{} {
d := hyperv.NewDriver(cfg.GetMachineName(), localpath.MiniPath())
d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO)
d.VSwitch = config.HypervVirtualSwitch
d.MemSize = config.Memory
......@@ -48,6 +57,19 @@ func createHypervHost(config cfg.MachineConfig) interface{} {
d.DiskSize = config.DiskSize
d.SSHUser = "docker"
d.DisableDynamicMemory = true // default to disable dynamic memory as minikube is unlikely to work properly with dynamic memory
return d
}
func status() registry.State {
path, err := exec.LookPath("powershell")
if err != nil {
return registry.State{Error: err}
}
cmd := exec.Command(path, "Get-WindowsOptionalFeature", "-FeatureName", "Microsoft-Hyper-V-All", "-Online")
out, err := cmd.CombinedOutput()
if err != nil {
return registry.State{Installed: false, Error: fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), out), Fix: "Start PowerShell as Administrator, and run: 'Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All'", Doc: docURL}
}
return registry.State{Installed: true, Healthy: true}
}
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Copyright 2019 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.
......@@ -14,16 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package drvs
import (
// Import all the default drivers
_ "k8s.io/minikube/pkg/minikube/drivers/hyperkit"
_ "k8s.io/minikube/pkg/minikube/drivers/hyperv"
_ "k8s.io/minikube/pkg/minikube/drivers/kvm2"
_ "k8s.io/minikube/pkg/minikube/drivers/none"
_ "k8s.io/minikube/pkg/minikube/drivers/parallels"
_ "k8s.io/minikube/pkg/minikube/drivers/virtualbox"
_ "k8s.io/minikube/pkg/minikube/drivers/vmware"
_ "k8s.io/minikube/pkg/minikube/drivers/vmwarefusion"
// Register all of the drvs we know of
_ "k8s.io/minikube/pkg/minikube/registry/drvs/hyperkit"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/hyperv"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/kvm2"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/none"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/parallels"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/virtualbox"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/vmware"
_ "k8s.io/minikube/pkg/minikube/registry/drvs/vmwarefusion"
)
......@@ -20,27 +20,34 @@ package kvm2
import (
"fmt"
"os/exec"
"path/filepath"
"strings"
"github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
const (
docURL = "https://minikube.sigs.k8s.io/docs/reference/drivers/kvm2/"
)
func init() {
if err := registry.Register(registry.DriverDef{
Name: constants.DriverKvm2,
Builtin: false,
ConfigCreator: createKVM2Host,
Name: driver.KVM2,
Config: configure,
Status: status,
Priority: registry.Preferred,
}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
}
// Delete this once the following PR is merged:
// https://github.com/dhiltgen/docker-machine-kvm/pull/68
// This is duplicate of kvm.Driver. Avoids importing the kvm2 driver, which requires cgo & libvirt.
type kvmDriver struct {
*drivers.BaseDriver
......@@ -57,23 +64,54 @@ type kvmDriver struct {
ConnectionURI string
}
func createKVM2Host(config cfg.MachineConfig) interface{} {
return &kvmDriver{
func configure(mc config.MachineConfig) interface{} {
name := config.GetMachineName()
return kvmDriver{
BaseDriver: &drivers.BaseDriver{
MachineName: cfg.GetMachineName(),
MachineName: name,
StorePath: localpath.MiniPath(),
SSHUser: "docker",
},
Memory: config.Memory,
CPU: config.CPUs,
Network: config.KVMNetwork,
Memory: mc.Memory,
CPU: mc.CPUs,
Network: mc.KVMNetwork,
PrivateNetwork: "minikube-net",
Boot2DockerURL: config.Downloader.GetISOFileURI(config.MinikubeISO),
DiskSize: config.DiskSize,
DiskPath: filepath.Join(localpath.MiniPath(), "machines", cfg.GetMachineName(), fmt.Sprintf("%s.rawdisk", cfg.GetMachineName())),
ISO: filepath.Join(localpath.MiniPath(), "machines", cfg.GetMachineName(), "boot2docker.iso"),
GPU: config.KVMGPU,
Hidden: config.KVMHidden,
ConnectionURI: config.KVMQemuURI,
Boot2DockerURL: mc.Downloader.GetISOFileURI(mc.MinikubeISO),
DiskSize: mc.DiskSize,
DiskPath: filepath.Join(localpath.MiniPath(), "machines", name, fmt.Sprintf("%s.rawdisk", name)),
ISO: filepath.Join(localpath.MiniPath(), "machines", name, "boot2docker.iso"),
GPU: mc.KVMGPU,
Hidden: mc.KVMHidden,
ConnectionURI: mc.KVMQemuURI,
}
}
func status() registry.State {
path, err := exec.LookPath("virsh")
if err != nil {
return registry.State{Error: err, Fix: "Install libvirt", Doc: docURL}
}
cmd := exec.Command(path, "domcapabilities", "--virttype", "kvm")
out, err := cmd.CombinedOutput()
if err != nil {
return registry.State{
Installed: true,
Error: fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), strings.TrimSpace(string(out))),
Fix: "Follow your Linux distribution instructions for configuring KVM",
Doc: docURL,
}
}
cmd = exec.Command("virsh", "list")
out, err = cmd.CombinedOutput()
if err != nil {
return registry.State{
Installed: true,
Error: fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), strings.TrimSpace(string(out))),
Fix: "Check that libvirtd is properly installed and that you are a member of the appropriate libvirt group",
Doc: docURL,
}
}
return registry.State{Installed: true, Healthy: true}
}
// +build linux
/*
Copyright 2018 The Kubernetes Authors All rights reserved.
......@@ -18,44 +20,40 @@ package none
import (
"fmt"
"os"
"os/exec"
"github.com/docker/machine/libmachine/drivers"
"k8s.io/minikube/pkg/drivers/none"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
func init() {
if err := registry.Register(registry.DriverDef{
Name: constants.DriverNone,
Builtin: true,
ConfigCreator: createNoneHost,
DriverCreator: func() drivers.Driver {
return none.NewDriver(none.Config{})
},
Name: driver.None,
Config: configure,
Init: func() drivers.Driver { return none.NewDriver(none.Config{}) },
Status: status,
Priority: registry.Discouraged, // requires root
}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
}
// createNoneHost creates a none Driver from a MachineConfig
func createNoneHost(config cfg.MachineConfig) interface{} {
func configure(mc config.MachineConfig) interface{} {
return none.NewDriver(none.Config{
MachineName: cfg.GetMachineName(),
MachineName: config.GetMachineName(),
StorePath: localpath.MiniPath(),
ContainerRuntime: config.ContainerRuntime,
ContainerRuntime: mc.ContainerRuntime,
})
}
// AutoOptions returns suggested extra options based on the current config
func AutoOptions() string {
// for more info see: https://github.com/kubernetes/minikube/issues/3511
f := "/run/systemd/resolve/resolv.conf"
if _, err := os.Stat(f); err != nil {
return ""
func status() registry.State {
_, err := exec.LookPath("systemctl")
if err != nil {
return registry.State{Error: err, Fix: "Use a systemd based Linux distribution", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"}
}
return fmt.Sprintf("kubelet.resolv-conf=%s", f)
return registry.State{Installed: true, Healthy: true}
}
......@@ -20,23 +20,23 @@ package parallels
import (
"fmt"
"os/exec"
parallels "github.com/Parallels/docker-machine-parallels"
"github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
func init() {
err := registry.Register(registry.DriverDef{
Name: constants.DriverParallels,
Builtin: true,
ConfigCreator: createParallelsHost,
DriverCreator: func() drivers.Driver {
return parallels.NewDriver("", "")
},
Name: driver.Parallels,
Config: configure,
Status: status,
Priority: registry.Default,
Init: func() drivers.Driver { return parallels.NewDriver("", "") },
})
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
......@@ -44,7 +44,7 @@ func init() {
}
func createParallelsHost(config cfg.MachineConfig) interface{} {
func configure(config cfg.MachineConfig) interface{} {
d := parallels.NewDriver(cfg.GetMachineName(), localpath.MiniPath()).(*parallels.Driver)
d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO)
d.Memory = config.Memory
......@@ -52,3 +52,11 @@ func createParallelsHost(config cfg.MachineConfig) interface{} {
d.DiskSize = config.DiskSize
return d
}
func status() registry.State {
_, err := exec.LookPath("docker-machine-driver-parallels")
if err != nil {
return registry.State{Error: err, Fix: "Install docker-machine-driver-parallels", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/parallels/"}
}
return registry.State{Installed: true, Healthy: true}
}
......@@ -18,45 +18,74 @@ package virtualbox
import (
"fmt"
"os/exec"
"strings"
"github.com/docker/machine/drivers/virtualbox"
"github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
const defaultVirtualboxNicType = "virtio"
const (
defaultVirtualboxNicType = "virtio"
docURL = "https://minikube.sigs.k8s.io/docs/reference/drivers/virtualbox/"
)
func init() {
err := registry.Register(registry.DriverDef{
Name: constants.DriverVirtualbox,
Builtin: true,
ConfigCreator: createVirtualboxHost,
DriverCreator: func() drivers.Driver {
return virtualbox.NewDriver("", "")
},
Name: driver.VirtualBox,
Config: configure,
Status: status,
Priority: registry.Fallback,
Init: func() drivers.Driver { return virtualbox.NewDriver("", "") },
})
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
}
}
func createVirtualboxHost(config cfg.MachineConfig) interface{} {
d := virtualbox.NewDriver(cfg.GetMachineName(), localpath.MiniPath())
d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO)
d.Memory = config.Memory
d.CPU = config.CPUs
d.DiskSize = config.DiskSize
d.HostOnlyCIDR = config.HostOnlyCIDR
d.NoShare = config.DisableDriverMounts
d.NoVTXCheck = config.NoVTXCheck
func configure(mc config.MachineConfig) interface{} {
d := virtualbox.NewDriver(config.GetMachineName(), localpath.MiniPath())
d.Boot2DockerURL = mc.Downloader.GetISOFileURI(mc.MinikubeISO)
d.Memory = mc.Memory
d.CPU = mc.CPUs
d.DiskSize = mc.DiskSize
d.HostOnlyCIDR = mc.HostOnlyCIDR
d.NoShare = mc.DisableDriverMounts
d.NoVTXCheck = mc.NoVTXCheck
d.NatNicType = defaultVirtualboxNicType
d.HostOnlyNicType = defaultVirtualboxNicType
d.DNSProxy = config.DNSProxy
d.HostDNSResolver = config.HostDNSResolver
d.DNSProxy = mc.DNSProxy
d.HostDNSResolver = mc.HostDNSResolver
return d
}
func status() registry.State {
// Re-use this function as it's particularly helpful for Windows
tryPath := driver.VBoxManagePath()
path, err := exec.LookPath(tryPath)
if err != nil {
return registry.State{
Error: fmt.Errorf("unable to find VBoxManage in $PATH"),
Fix: "Install VirtualBox",
Doc: docURL,
}
}
cmd := exec.Command(path, "list", "hostinfo")
out, err := cmd.CombinedOutput()
if err != nil {
return registry.State{
Installed: true,
Error: fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), out),
Fix: "Install the latest version of VirtualBox",
Doc: docURL,
}
}
return registry.State{Installed: true, Healthy: true}
}
......@@ -18,34 +18,48 @@ package vmware
import (
"fmt"
"os/exec"
vmwcfg "github.com/machine-drivers/docker-machine-driver-vmware/pkg/drivers/vmware/config"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
func init() {
err := registry.Register(registry.DriverDef{
Name: constants.DriverVmware,
Builtin: false,
ConfigCreator: createVMwareHost,
Name: driver.VMware,
Config: configure,
Priority: registry.Default,
Status: status,
})
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
}
}
func createVMwareHost(config cfg.MachineConfig) interface{} {
d := vmwcfg.NewConfig(cfg.GetMachineName(), localpath.MiniPath())
d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO)
d.Memory = config.Memory
d.CPU = config.CPUs
d.DiskSize = config.DiskSize
func configure(mc config.MachineConfig) interface{} {
d := vmwcfg.NewConfig(config.GetMachineName(), localpath.MiniPath())
d.Boot2DockerURL = mc.Downloader.GetISOFileURI(mc.MinikubeISO)
d.Memory = mc.Memory
d.CPU = mc.CPUs
d.DiskSize = mc.DiskSize
// TODO(frapposelli): push these defaults upstream to fixup this driver
d.SSHPort = 22
d.ISO = d.ResolveStorePath("boot2docker.iso")
return d
}
func status() registry.State {
_, err := exec.LookPath("docker-machine-driver-vmware")
if err != nil {
return registry.State{Error: err, Fix: "Install docker-machine-driver-vmware", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/vmware/"}
}
_, err = exec.LookPath("vmrun")
if err != nil {
return registry.State{Error: err, Fix: "Install vmrun", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/vmware/"}
}
return registry.State{Installed: true, Healthy: true}
}
......@@ -20,29 +20,31 @@ package vmwarefusion
import (
"fmt"
"os/exec"
"github.com/docker/machine/drivers/vmwarefusion"
"github.com/docker/machine/libmachine/drivers"
"github.com/pkg/errors"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
)
func init() {
if err := registry.Register(registry.DriverDef{
Name: constants.DriverVmwareFusion,
Builtin: true,
ConfigCreator: createVMwareFusionHost,
DriverCreator: func() drivers.Driver {
return vmwarefusion.NewDriver("", "")
},
Name: driver.VMwareFusion,
Config: configure,
Status: status,
Init: func() drivers.Driver { return vmwarefusion.NewDriver("", "") },
Priority: registry.Deprecated,
}); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
}
func createVMwareFusionHost(config cfg.MachineConfig) interface{} {
func configure(config cfg.MachineConfig) interface{} {
d := vmwarefusion.NewDriver(cfg.GetMachineName(), localpath.MiniPath()).(*vmwarefusion.Driver)
d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO)
d.Memory = config.Memory
......@@ -54,3 +56,11 @@ func createVMwareFusionHost(config cfg.MachineConfig) interface{} {
d.ISO = d.ResolveStorePath("boot2docker.iso")
return d
}
func status() registry.State {
_, err := exec.LookPath("vmrun")
if err != nil {
return registry.State{Error: errors.Wrap(err, "vmrun path check"), Fix: "Install VMWare Fusion", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/vmwarefusion/"}
}
return registry.State{Installed: true, Healthy: true}
}
/*
Copyright 2018 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 registry
import (
"os"
"github.com/golang/glog"
)
var (
// globalRegistry is a globally accessible driver registry
globalRegistry = newRegistry()
)
// DriverState is metadata relating to a driver and status
type DriverState struct {
Name string
Priority Priority
State State
}
func (d DriverState) String() string {
return d.Name
}
// List lists drivers in global registry
func List() []DriverDef {
return globalRegistry.List()
}
// Register registers driver with the global registry
func Register(driver DriverDef) error {
return globalRegistry.Register(driver)
}
// Driver gets a named driver from the global registry
func Driver(name string) DriverDef {
return globalRegistry.Driver(name)
}
// Installed returns a list of installed drivers in the global registry
func Installed() []DriverState {
sts := []DriverState{}
glog.Infof("Querying for installed drivers using PATH=%s", os.Getenv("PATH"))
for _, d := range globalRegistry.List() {
if d.Status == nil {
glog.Errorf("%q does not implement Status", d.Name)
continue
}
s := d.Status()
glog.Infof("%s priority: %d, state: %+v", d.Name, d.Priority, s)
if !s.Installed {
glog.Infof("%q not installed: %v", d.Name, s.Error)
continue
}
sts = append(sts, DriverState{Name: d.Name, Priority: d.Priority, State: s})
}
return sts
}
// Status returns the state of a driver within the global registry
func Status(name string) State {
d := globalRegistry.Driver(name)
if d.Empty() {
return State{}
}
return d.Status()
}
/*
Copyright 2018 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 registry
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestGlobalRegister(t *testing.T) {
globalRegistry = newRegistry()
foo := DriverDef{Name: "foo"}
if err := Register(foo); err != nil {
t.Errorf("Register = %v, expected nil", err)
}
if err := Register(foo); err == nil {
t.Errorf("Register = nil, expected duplicate err")
}
}
func TestGlobalDriver(t *testing.T) {
foo := DriverDef{Name: "foo"}
globalRegistry = newRegistry()
if err := Register(foo); err != nil {
t.Errorf("Register = %v, expected nil", err)
}
d := Driver("foo")
if d.Empty() {
t.Errorf("driver.Empty = true, expected false")
}
d = Driver("bar")
if !d.Empty() {
t.Errorf("driver.Empty = false, expected true")
}
}
func TestGlobalList(t *testing.T) {
foo := DriverDef{Name: "foo"}
globalRegistry = newRegistry()
if err := Register(foo); err != nil {
t.Errorf("register returned error: %v", err)
}
if diff := cmp.Diff(List(), []DriverDef{foo}); diff != "" {
t.Errorf("list mismatch (-want +got):\n%s", diff)
}
}
func TestGlobalInstalled(t *testing.T) {
globalRegistry = newRegistry()
if err := Register(DriverDef{Name: "foo"}); err != nil {
t.Errorf("register returned error: %v", err)
}
bar := DriverDef{
Name: "bar",
Priority: Default,
Status: func() State { return State{Installed: true} },
}
if err := Register(bar); err != nil {
t.Errorf("register returned error: %v", err)
}
expected := []DriverState{
DriverState{
Name: "bar",
Priority: Default,
State: State{
Installed: true,
},
},
}
if diff := cmp.Diff(Installed(), expected); diff != "" {
t.Errorf("installed mismatch (-want +got):\n%s", diff)
}
}
func TestGlobalStatus(t *testing.T) {
globalRegistry = newRegistry()
if err := Register(DriverDef{Name: "foo"}); err != nil {
t.Errorf("register returned error: %v", err)
}
expected := State{Installed: true, Healthy: true}
bar := DriverDef{
Name: "bar",
Priority: Default,
Status: func() State { return expected },
}
if err := Register(bar); err != nil {
t.Errorf("register returned error: %v", err)
}
if diff := cmp.Diff(Status("bar"), expected); diff != "" {
t.Errorf("status mismatch (-want +got):\n%s", diff)
}
}
......@@ -21,18 +21,21 @@ import (
"sync"
"github.com/docker/machine/libmachine/drivers"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/config"
)
var (
// ErrDriverNameExist is the error returned when trying to register a driver
// which already exists in registry
ErrDriverNameExist = errors.New("registry: duplicated driver name")
// ErrDriverNotFound is the error returned when driver of a given name does
// not exist in registry
ErrDriverNotFound = errors.New("registry: driver not found")
// Priority is how we determine what driver to default to
type Priority int
const (
Unknown Priority = iota
Discouraged
Deprecated
Fallback
Default
Preferred
StronglyPreferred
)
// Registry contains all the supported driver definitions on the host
......@@ -47,31 +50,49 @@ type Registry interface {
List() []DriverDef
}
// ConfigFactory is a function that creates a driver config from MachineConfig
type ConfigFactory func(config.MachineConfig) interface{}
// Configurator emits a struct to be marshalled into JSON for Machine Driver
type Configurator func(config.MachineConfig) interface{}
// Loader is a function that loads a byte stream and creates a driver.
type Loader func() drivers.Driver
// DriverFactory is a function that loads a byte stream and creates a driver.
type DriverFactory func() drivers.Driver
// StatusChecker checks if a driver is available, offering a
type StatusChecker func() State
// State is the current state of the driver and its dependencies
type State struct {
Installed bool
Healthy bool
Error error
Fix string
Doc string
}
// DriverDef defines a machine driver metadata. It tells minikube how to initialize
// and load drivers.
// DriverDef defines how to initialize and load a machine driver
type DriverDef struct {
// Name of the machine driver. It has to be unique.
Name string
// BuiltIn indicates if the driver is builtin minikube binary, or the driver is
// triggered through RPC.
Builtin bool
// Config is a function that emits a configured driver struct
Config Configurator
// ConfigCreator generates a raw driver object by minikube's machine config.
ConfigCreator ConfigFactory
// Init is a function that initializes a machine driver, if built-in to the minikube binary
Init Loader
// DriverCreator is the factory method that creates a machine driver instance.
DriverCreator DriverFactory
// Status returns the installation status of the driver
Status StatusChecker
// Priority returns the prioritization for selecting a driver by default.
Priority Priority
}
// Empty returns true if the driver is nil
func (d DriverDef) Empty() bool {
return d.Name == ""
}
func (d DriverDef) String() string {
return fmt.Sprintf("{name: %s, builtin: %t}", d.Name, d.Builtin)
return d.Name
}
type driverRegistry struct {
......@@ -79,43 +100,26 @@ type driverRegistry struct {
lock sync.Mutex
}
func createRegistry() *driverRegistry {
func newRegistry() *driverRegistry {
return &driverRegistry{
drivers: make(map[string]DriverDef),
}
}
var (
registry = createRegistry()
)
// ListDrivers lists all drivers in registry
func ListDrivers() []DriverDef {
return registry.List()
}
// Register registers driver
func Register(driver DriverDef) error {
return registry.Register(driver)
}
// Driver gets a named driver
func Driver(name string) (DriverDef, error) {
return registry.Driver(name)
}
// Register registers a driver
func (r *driverRegistry) Register(def DriverDef) error {
r.lock.Lock()
defer r.lock.Unlock()
if _, ok := r.drivers[def.Name]; ok {
return ErrDriverNameExist
return fmt.Errorf("%q is already registered: %+v", def.Name, def)
}
r.drivers[def.Name] = def
return nil
}
// List returns a list of registered drivers
func (r *driverRegistry) List() []DriverDef {
r.lock.Lock()
defer r.lock.Unlock()
......@@ -129,13 +133,9 @@ func (r *driverRegistry) List() []DriverDef {
return result
}
func (r *driverRegistry) Driver(name string) (DriverDef, error) {
// Driver returns a driver given a name
func (r *driverRegistry) Driver(name string) DriverDef {
r.lock.Lock()
defer r.lock.Unlock()
if driver, ok := r.drivers[name]; ok {
return driver, nil
}
return DriverDef{}, ErrDriverNotFound
return r.drivers[name]
}
......@@ -19,107 +19,47 @@ package registry
import (
"testing"
"k8s.io/minikube/pkg/minikube/config"
"github.com/google/go-cmp/cmp"
)
func TestDriverString(t *testing.T) {
bar := DriverDef{
Name: "bar",
Builtin: true,
ConfigCreator: func(_ config.MachineConfig) interface{} {
return nil
},
func TestRegister(t *testing.T) {
r := newRegistry()
foo := DriverDef{Name: "foo"}
if err := r.Register(foo); err != nil {
t.Errorf("Register = %v, expected nil", err)
}
s := bar.String()
if s != "{name: bar, builtin: true}" {
t.Fatalf("Driver bar.String() returned unexpected: %v", s)
if err := r.Register(foo); err == nil {
t.Errorf("Register = nil, expected duplicate err")
}
}
func testDriver(name string) DriverDef {
return DriverDef{
Name: name,
Builtin: true,
ConfigCreator: func(_ config.MachineConfig) interface{} {
return nil
},
func TestDriver(t *testing.T) {
foo := DriverDef{Name: "foo"}
r := newRegistry()
if err := r.Register(foo); err != nil {
t.Errorf("Register = %v, expected nil", err)
}
}
func TestRegistry1(t *testing.T) {
foo := testDriver("foo")
bar := testDriver("bar")
d := r.Driver("foo")
if d.Empty() {
t.Errorf("driver.Empty = true, expected false")
}
registry := createRegistry()
t.Run("registry.Register", func(t *testing.T) {
t.Run("foo", func(t *testing.T) {
if err := registry.Register(foo); err != nil {
t.Fatalf("error not expected but got %v", err)
}
})
t.Run("fooAlreadyExist", func(t *testing.T) {
if err := registry.Register(foo); err != ErrDriverNameExist {
t.Fatalf("expect ErrDriverNameExist but got: %v", err)
}
})
t.Run("bar", func(t *testing.T) {
if err := registry.Register(bar); err != nil {
t.Fatalf("error not expect but got: %v", err)
}
})
})
t.Run("registry.List", func(t *testing.T) {
list := registry.List()
if !(list[0].Name == "bar" && list[1].Name == "foo" ||
list[0].Name == "foo" && list[1].Name == "bar") {
t.Fatalf("expect registry.List return %s; got %s", []string{"bar", "foo"}, list)
}
if drivers := ListDrivers(); len(list) == len(drivers) {
t.Fatalf("Expectect ListDrivers and registry.List() to return same number of items, but got: drivers=%v and list=%v", drivers, list)
} else if len(list) == len(drivers) {
t.Fatalf("expect len(list) to be %d; got %d", 2, len(list))
}
})
d = r.Driver("bar")
if !d.Empty() {
t.Errorf("driver.Empty = false, expected true")
}
}
func TestRegistry2(t *testing.T) {
foo := testDriver("foo")
bar := testDriver("bar")
registry := createRegistry()
if err := registry.Register(foo); err != nil {
t.Skipf("error not expect but got: %v", err)
}
if err := registry.Register(bar); err != nil {
t.Skipf("error not expect but got: %v", err)
func TestList(t *testing.T) {
foo := DriverDef{Name: "foo"}
r := newRegistry()
if err := r.Register(foo); err != nil {
t.Errorf("register returned error: %v", err)
}
t.Run("Driver", func(t *testing.T) {
driverName := "foo"
driver, err := registry.Driver(driverName)
if err != nil {
t.Fatalf("expect nil for registering foo driver, but got: %v", err)
}
if driver.Name != driverName {
t.Fatalf("expect registry.Driver(%s) returns registered driver, but got: %s", driverName, driver.Name)
}
})
t.Run("NotExistingDriver", func(t *testing.T) {
_, err := registry.Driver("foo2")
if err != ErrDriverNotFound {
t.Fatalf("expect ErrDriverNotFound bug got: %v", err)
}
})
t.Run("Driver", func(t *testing.T) {
if _, err := Driver("no_such_driver"); err == nil {
t.Fatal("expect to get error for not existing driver")
}
})
if _, err := Driver("foo"); err == nil {
t.Fatal("expect to not get error during existing driver foo")
if diff := cmp.Diff(r.List(), []DriverDef{foo}); diff != "" {
t.Errorf("list mismatch (-want +got):\n%s", diff)
}
t.Run("Register", func(t *testing.T) {
if err := Register(foo); err != nil {
t.Fatalf("expect to not get error during registering driver foo, but got: %v", err)
}
})
}
......@@ -67,14 +67,14 @@ func (api *MockAPI) Close() error {
}
// NewHost creates a new host.Host instance.
func (api *MockAPI) NewHost(driverName string, rawDriver []byte) (*host.Host, error) {
func (api *MockAPI) NewHost(drvName string, rawDriver []byte) (*host.Host, error) {
var driver MockDriver
if err := json.Unmarshal(rawDriver, &driver); err != nil {
return nil, errors.Wrap(err, "error unmarshalling json")
}
h := &host.Host{
DriverName: driverName,
DriverName: drvName,
RawDriver: rawDriver,
Driver: &MockDriver{},
Name: fmt.Sprintf("mock-machine-%.8f", rand.Float64()),
......
......@@ -19,8 +19,6 @@ package tests
import (
"testing"
"k8s.io/minikube/pkg/minikube/constants"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/mcnflag"
"github.com/docker/machine/libmachine/state"
......@@ -40,111 +38,111 @@ type MockDriver struct {
}
// Logf logs mock interactions
func (driver *MockDriver) Logf(format string, args ...interface{}) {
if driver.T == nil {
func (d *MockDriver) Logf(format string, args ...interface{}) {
if d.T == nil {
glog.Infof(format, args...)
return
}
driver.T.Logf(format, args...)
d.T.Logf(format, args...)
}
// Create creates a MockDriver instance
func (driver *MockDriver) Create() error {
driver.Logf("MockDriver.Create")
driver.CurrentState = state.Running
func (d *MockDriver) Create() error {
d.Logf("MockDriver.Create")
d.CurrentState = state.Running
return nil
}
// GetIP returns the IP address
func (driver *MockDriver) GetIP() (string, error) {
driver.Logf("MockDriver.GetIP")
if driver.IP != "" {
return driver.IP, nil
func (d *MockDriver) GetIP() (string, error) {
d.Logf("MockDriver.GetIP")
if d.IP != "" {
return d.IP, nil
}
if driver.BaseDriver.IPAddress != "" {
return driver.BaseDriver.IPAddress, nil
if d.BaseDriver.IPAddress != "" {
return d.BaseDriver.IPAddress, nil
}
return "127.0.0.1", nil
}
// GetCreateFlags returns the flags used to create a MockDriver
func (driver *MockDriver) GetCreateFlags() []mcnflag.Flag {
func (d *MockDriver) GetCreateFlags() []mcnflag.Flag {
return []mcnflag.Flag{}
}
// GetSSHPort returns the SSH port
func (driver *MockDriver) GetSSHPort() (int, error) {
return driver.Port, nil
func (d *MockDriver) GetSSHPort() (int, error) {
return d.Port, nil
}
// GetSSHHostname returns the hostname for SSH
func (driver *MockDriver) GetSSHHostname() (string, error) {
if driver.HostError {
func (d *MockDriver) GetSSHHostname() (string, error) {
if d.HostError {
return "", errors.New("error getting host")
}
return "localhost", nil
}
// GetSSHKeyPath returns the key path for SSH
func (driver *MockDriver) GetSSHKeyPath() string {
return driver.BaseDriver.SSHKeyPath
func (d *MockDriver) GetSSHKeyPath() string {
return d.BaseDriver.SSHKeyPath
}
// GetState returns the state of the driver
func (driver *MockDriver) GetState() (state.State, error) {
driver.Logf("MockDriver.GetState: %v", driver.CurrentState)
return driver.CurrentState, nil
func (d *MockDriver) GetState() (state.State, error) {
d.Logf("MockDriver.GetState: %v", d.CurrentState)
return d.CurrentState, nil
}
// GetURL returns the URL of the driver
func (driver *MockDriver) GetURL() (string, error) {
func (d *MockDriver) GetURL() (string, error) {
return "", nil
}
// Kill kills the machine
func (driver *MockDriver) Kill() error {
driver.Logf("MockDriver.Kill")
driver.CurrentState = state.Stopped
func (d *MockDriver) Kill() error {
d.Logf("MockDriver.Kill")
d.CurrentState = state.Stopped
return nil
}
// Remove removes the machine
func (driver *MockDriver) Remove() error {
driver.Logf("MockDriver.Remove")
if driver.RemoveError {
func (d *MockDriver) Remove() error {
d.Logf("MockDriver.Remove")
if d.RemoveError {
return errors.New("error deleting machine")
}
return nil
}
// Restart restarts the machine
func (driver *MockDriver) Restart() error {
driver.Logf("MockDriver.Restart")
driver.CurrentState = state.Running
func (d *MockDriver) Restart() error {
d.Logf("MockDriver.Restart")
d.CurrentState = state.Running
return nil
}
// SetConfigFromFlags sets the machine config
func (driver *MockDriver) SetConfigFromFlags(opts drivers.DriverOptions) error {
func (d *MockDriver) SetConfigFromFlags(opts drivers.DriverOptions) error {
return nil
}
// Start starts the machine
func (driver *MockDriver) Start() error {
driver.Logf("MockDriver.Start")
driver.CurrentState = state.Running
func (d *MockDriver) Start() error {
d.Logf("MockDriver.Start")
d.CurrentState = state.Running
return nil
}
// Stop stops the machine
func (driver *MockDriver) Stop() error {
driver.Logf("MockDriver.Stop")
driver.CurrentState = state.Stopped
func (d *MockDriver) Stop() error {
d.Logf("MockDriver.Stop")
d.CurrentState = state.Stopped
return nil
}
// DriverName returns the name of the driver
func (driver *MockDriver) DriverName() string {
driver.Logf("MockDriver.Name")
return constants.DriverMock
func (d *MockDriver) DriverName() string {
d.Logf("MockDriver.Name")
return "mock"
}
......@@ -29,7 +29,7 @@ import (
"github.com/pkg/errors"
typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
)
// tunnel represents the basic API for a tunnel: periodically the state of the tunnel
......@@ -150,7 +150,7 @@ func setupRoute(t *tunnel, h *host.Host) {
return
}
if h.DriverName == constants.DriverHyperkit {
if h.DriverName == driver.HyperKit {
// the virtio-net interface acts up with ip tunnels :(
setupBridge(t)
if t.status.RouteError != nil {
......
......@@ -89,8 +89,8 @@ func escapeSystemdDirectives(engineConfigContext *provision.EngineConfigContext)
func (p *BuildrootProvisioner) GenerateDockerOptions(dockerPort int) (*provision.DockerOptions, error) {
var engineCfg bytes.Buffer
driverNameLabel := fmt.Sprintf("provider=%s", p.Driver.DriverName())
p.EngineOptions.Labels = append(p.EngineOptions.Labels, driverNameLabel)
drvLabel := fmt.Sprintf("provider=%s", p.Driver.DriverName())
p.EngineOptions.Labels = append(p.EngineOptions.Labels, drvLabel)
noPivot := true
// Using pivot_root is not supported on fstype rootfs
......
......@@ -9,7 +9,7 @@ theme = ["docsy"]
enableGitInfo = true
# Language settings
contentDir = "content/en"
contentDir = "content/en"
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = false
# Useful when translating.
......@@ -33,6 +33,30 @@ pygmentsStyle = "tango"
[permalinks]
blog = "/:section/:year/:month/:day/:slug/"
[module]
[[module.mounts]]
source = "../deploy/addons/gvisor/"
target = "content/gvisor/"
[[module.mounts]]
source = "../deploy/addons/helm-tiller/"
target = "content/helm-tiller/"
[[module.mounts]]
source = "../deploy/addons/ingress-dns/"
target = "content/ingress-dns/"
[[module.mounts]]
source = "../deploy/addons/storage-provisioner-gluster/"
target = "content/storage-provisioner-gluster/"
[[module.mounts]]
source = "../deploy/addons/layouts/"
target = "layouts"
[[module.mounts]]
source = "content/en"
target = "content"
[[module.mounts]]
source = "layouts"
target = "layouts"
## Configuration for BlackFriday markdown parser: https://github.com/russross/blackfriday
[blackfriday]
plainIDAnchors = true
......@@ -68,7 +92,7 @@ weight = 1
[params]
copyright = "The Kubernetes Authors -- "
# The latest release of minikube
latest_release = "1.4.0"
latest_release = "1.5.0"
privacy_policy = ""
......
......@@ -79,6 +79,8 @@ This step uses the git tag to publish new binaries to GCS and create a github re
After job completion, click "Console Output" to verify that the release completed without errors. This is typically where one will see brew automation fail, for instance.
**Note: If you are releasing a beta, you are done when you get here.**
## Check releases.json
This file is used for auto-update notifications, but is not active until releases.json is copied to GCS.
......
......@@ -39,3 +39,7 @@ Stop your local cluster:
Delete your local cluster:
`minikube delete`
Delete all local clusters and profiles
`minikube delete --all`
......@@ -4,7 +4,7 @@
## Usage
minikube currently uses VirtualBox by default, but it can also be explicitly set:
Start a cluster using the virtualbox driver:
```shell
minikube start --vm-driver=virtualbox
......
......@@ -20,10 +20,10 @@ minikube has a set of built-in addons that, when enabled, can be used within Kub
* [nvidia-driver-installer](https://github.com/GoogleCloudPlatform/container-engine-accelerators/tree/master/nvidia-driver-installer/minikube)
* [nvidia-gpu-device-plugin](https://github.com/GoogleCloudPlatform/container-engine-accelerators/tree/master/cmd/nvidia_gpu)
* [logviewer](https://github.com/ivans3/minikube-log-viewer)
* [gvisor](../deploy/addons/gvisor/README.md)
* [storage-provisioner-gluster](../deploy/addons/storage-provisioner-gluster/README.md)
* [helm-tiller](../deploy/addons/helm-tiller/README.md)
* [ingress-dns](../deploy/addons/ingress-dns/README.md)
* [gvisor](../../../gvisor/readme/)
* [storage-provisioner-gluster](../../../storage-provisioner-gluster/readme)
* [helm-tiller](../../../helm-tiller/readme)
* [ingress-dns](../../../ingress-dns/readme)
## Listing available addons
......
......@@ -33,9 +33,11 @@ fi
if [[ "$TESTSUITE" = "boilerplate" ]] || [[ "$TESTSUITE" = "all" ]]
then
echo "= boilerplate ==========================================================="
readonly PYTHON=$(type -P python || echo docker run --rm -it -v $(pwd):/minikube -w /minikube python python)
readonly BDIR="./hack/boilerplate"
missing="$($PYTHON ${BDIR}/boilerplate.py --rootdir . --boilerplate-dir ${BDIR} | egrep -v '/assets.go|/translations.go|/site/themes/|/site/node_modules|\./out|/hugo/' || true)"
readonly ROOT_DIR=$(pwd)
readonly BDIR="${ROOT_DIR}/hack/boilerplate"
pushd . >/dev/null
cd ${BDIR}
missing="$(go run boilerplate.go -rootdir ${ROOT_DIR} -boilerplate-dir ${BDIR} | egrep -v '/assets.go|/translations.go|/site/themes/|/site/node_modules|\./out|/hugo/' || true)"
if [[ -n "${missing}" ]]; then
echo "boilerplate missing: $missing"
echo "consider running: ${BDIR}/fix.sh"
......@@ -43,6 +45,7 @@ then
else
echo "ok"
fi
popd >/dev/null
fi
......
......@@ -10,7 +10,7 @@ To run all tests from the minikube root directory:
Run a single test on an active cluster:
`make integration -e TEST_ARGS="-test.v -test.run TestFunctional/parallel/MountCmd --profile=minikube --cleanup=false"`
`make integration -e TEST_ARGS="-test.run TestFunctional/parallel/MountCmd --profile=minikube --cleanup=false"`
WARNING: For this to work repeatedly, the test must be written so that it cleans up after itself.
......
......@@ -20,6 +20,7 @@ package integration
import (
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
......@@ -29,15 +30,20 @@ import (
"time"
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/localpath"
)
func TestDownloadAndDeleteAll(t *testing.T) {
func TestDownloadOnly(t *testing.T) {
profile := UniqueProfileName("download")
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer Cleanup(t, profile, cancel)
// Stores the startup run result for later error messages
var rrr *RunResult
var err error
t.Run("group", func(t *testing.T) {
versions := []string{
constants.OldestKubernetesVersion,
......@@ -46,22 +52,28 @@ func TestDownloadAndDeleteAll(t *testing.T) {
}
for _, v := range versions {
t.Run(v, func(t *testing.T) {
args := append([]string{"start", "--download-only", "-p", profile, fmt.Sprintf("--kubernetes-version=%s", v)}, StartArgs()...)
_, err := Run(t, exec.CommandContext(ctx, Target(), args...))
// Explicitly does not pass StartArgs() to test driver default
// --force to avoid uid check
args := []string{"start", "--download-only", "-p", profile, "--force", "--alsologtostderr", fmt.Sprintf("--kubernetes-version=%s", v)}
// Preserve the initial run-result for debugging
if rrr == nil {
rrr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
} else {
_, err = Run(t, exec.CommandContext(ctx, Target(), args...))
}
if err != nil {
t.Errorf("%s failed: %v", args, err)
}
// None driver does not cache images, so this test will fail
if !NoneDriver() {
imgs := images.CachedImages("", v)
for _, img := range imgs {
img = strings.Replace(img, ":", "_", 1) // for example kube-scheduler:v1.15.2 --> kube-scheduler_v1.15.2
fp := filepath.Join(localpath.MiniPath(), "cache", "images", img)
_, err := os.Stat(fp)
if err != nil {
t.Errorf("expected image file exist at %q but got error: %v", fp, err)
}
imgs := images.CachedImages("", v)
for _, img := range imgs {
img = strings.Replace(img, ":", "_", 1) // for example kube-scheduler:v1.15.2 --> kube-scheduler_v1.15.2
fp := filepath.Join(localpath.MiniPath(), "cache", "images", img)
_, err := os.Stat(fp)
if err != nil {
t.Errorf("expected image file exist at %q but got error: %v", fp, err)
}
}
......@@ -75,8 +87,40 @@ func TestDownloadAndDeleteAll(t *testing.T) {
}
})
}
// Check that the profile we've created has the expected driver
t.Run("ExpectedDefaultDriver", func(t *testing.T) {
if ExpectedDefaultDriver() == "" {
t.Skipf("--expected-default-driver is unset, skipping test")
return
}
rr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list", "--output", "json"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
var ps map[string][]config.Profile
err = json.Unmarshal(rr.Stdout.Bytes(), &ps)
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
got := ""
for _, p := range ps["valid"] {
if p.Name == profile {
got = p.Config.MachineConfig.VMDriver
}
}
if got != ExpectedDefaultDriver() {
t.Errorf("got driver %q, expected %q\nstart output: %s", got, ExpectedDefaultDriver(), rrr.Output())
}
})
// This is a weird place to test profile deletion, but this test is serial, and we have a profile to delete!
t.Run("DeleteAll", func(t *testing.T) {
if !CanCleanup() {
t.Skip("skipping, as cleanup is disabled")
}
rr, err := Run(t, exec.CommandContext(ctx, Target(), "delete", "--all"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
......@@ -84,6 +128,9 @@ func TestDownloadAndDeleteAll(t *testing.T) {
})
// Delete should always succeed, even if previously partially or fully deleted.
t.Run("DeleteAlwaysSucceeds", func(t *testing.T) {
if !CanCleanup() {
t.Skip("skipping, as cleanup is disabled")
}
rr, err := Run(t, exec.CommandContext(ctx, Target(), "delete", "-p", profile))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
......
......@@ -26,7 +26,7 @@ import (
"github.com/blang/semver"
"k8s.io/minikube/pkg/drivers"
"k8s.io/minikube/pkg/minikube/driver"
)
func TestKVMDriverInstallOrUpdate(t *testing.T) {
......@@ -84,7 +84,7 @@ func TestKVMDriverInstallOrUpdate(t *testing.T) {
t.Fatalf("Expected new semver. test: %v, got: %v", tc.name, err)
}
err = drivers.InstallOrUpdate("kvm2", dir, newerVersion, true, true)
err = driver.InstallOrUpdate("kvm2", dir, newerVersion, true, true)
if err != nil {
t.Fatalf("Failed to update driver to %v. test: %s, got: %v", newerVersion, tc.name, err)
}
......@@ -147,7 +147,7 @@ func TestHyperKitDriverInstallOrUpdate(t *testing.T) {
t.Fatalf("Expected new semver. test: %v, got: %v", tc.name, err)
}
err = drivers.InstallOrUpdate("hyperkit", dir, newerVersion, true, true)
err = driver.InstallOrUpdate("hyperkit", dir, newerVersion, true, true)
if err != nil {
t.Fatalf("Failed to update driver to %v. test: %s, got: %v", newerVersion, tc.name, err)
}
......
......@@ -84,6 +84,7 @@ func TestFunctional(t *testing.T) {
{"ConfigCmd", validateConfigCmd},
{"DashboardCmd", validateDashboardCmd},
{"DNS", validateDNS},
{"StatusCmd", validateStatusCmd},
{"LogsCmd", validateLogsCmd},
{"MountCmd", validateMountCmd},
{"ProfileCmd", validateProfileCmd},
......@@ -175,6 +176,46 @@ func validateComponentHealth(ctx context.Context, t *testing.T, profile string)
}
}
func validateStatusCmd(ctx context.Context, t *testing.T, profile string) {
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
// Custom format
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status", "-f", "host:{{.Host}},kublet:{{.Kubelet}},apiserver:{{.APIServer}},kubeconfig:{{.Kubeconfig}}"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
match, _ := regexp.MatchString(`host:([A-z]+),kublet:([A-z]+),apiserver:([A-z]+),kubeconfig:([A-z]+)`, rr.Stdout.String())
if !match {
t.Errorf("%s failed: %v. Output for custom format did not match", rr.Args, err)
}
// Json output
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status", "-o", "json"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
var jsonObject map[string]interface{}
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonObject)
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
if _, ok := jsonObject["Host"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "Host")
}
if _, ok := jsonObject["Kubelet"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "Kubelet")
}
if _, ok := jsonObject["APIServer"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "APIServer")
}
if _, ok := jsonObject["Kubeconfig"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "Kubeconfig")
}
}
// validateDashboardCmd asserts that the dashboard command works
func validateDashboardCmd(ctx context.Context, t *testing.T, profile string) {
args := []string{"dashboard", "--url", "-p", profile, "--alsologtostderr", "-v=1"}
......
......@@ -35,6 +35,13 @@ func TestGvisorAddon(t *testing.T) {
profile := UniqueProfileName("gvisor")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
defer func() {
if t.Failed() {
rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "logs", "gvisor", "-n", "kube-system"))
if err != nil {
t.Logf("failed to get gvisor post-mortem logs: %v", err)
}
t.Logf("gvisor post-mortem: %s:\n%s\n", rr.Command(), rr.Output())
}
CleanupWithLogs(t, profile, cancel)
}()
......@@ -44,10 +51,10 @@ func TestGvisorAddon(t *testing.T) {
t.Fatalf("%s failed: %v", rr.Args, err)
}
// TODO: Re-examine if we should be pulling in an image which users don't normally invoke
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "cache", "add", "gcr.io/k8s-minikube/gvisor-addon:latest"))
// If it exists, include a locally built gvisor image
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "cache", "add", "gcr.io/k8s-minikube/gvisor-addon:2"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
t.Logf("%s failed: %v (won't test local image)", rr.Args, err)
}
// NOTE: addons are global, but the addon must assert that the runtime is containerd
......
......@@ -27,6 +27,7 @@ import (
// General configuration: used to set the VM Driver
var startArgs = flag.String("minikube-start-args", "", "Arguments to pass to minikube start")
var defaultDriver = flag.String("expected-default-driver", "", "Expected default driver")
// Flags for faster local integration testing
var forceProfile = flag.String("profile", "", "force tests to run against a particular profile")
......@@ -65,3 +66,13 @@ func NoneDriver() bool {
func HyperVDriver() bool {
return strings.Contains(*startArgs, "--vm-driver=hyperv")
}
// ExpectedDefaultDriver returns the expected default driver, if any
func ExpectedDefaultDriver() string {
return *defaultDriver
}
// CanCleanup returns if cleanup is allowed
func CanCleanup() bool {
return *cleanup
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册