diff --git a/.travis.yml b/.travis.yml
index 39089ee1503c..123568d3cb9c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 350f30fd8e66..c0b16d2b4b51 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,27 @@
# 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)
diff --git a/Makefile b/Makefile
index f1c0296142f1..cc2907f480f6 100755
--- a/Makefile
+++ b/Makefile
@@ -15,12 +15,12 @@
# 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)
# Default to .0 for higher cache hit rates, as build increments typically don't require new ISO versions
-ISO_VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).0-beta.0
+ISO_VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).0
# Dashes are valid in semver, but not Linux packaging. Use ~ to delimit alpha/beta
DEB_VERSION ?= $(subst -,~,$(RAW_VERSION))
RPM_VERSION ?= $(DEB_VERSION)
@@ -51,7 +51,7 @@ MINIKUBE_RELEASES_URL=https://github.com/kubernetes/minikube/releases/download
KERNEL_VERSION ?= 4.19.76
# latest from https://github.com/golangci/golangci-lint/releases
-GOLINT_VERSION ?= v1.20.0
+GOLINT_VERSION ?= v1.21.0
# Limit number of default jobs, to avoid the CI builds running out of memory
GOLINT_JOBS ?= 4
# see https://github.com/golangci/golangci-lint#memory-usage-of-golangci-lint
@@ -59,9 +59,11 @@ GOLINT_GOGC ?= 100
# options for lint (golangci-lint)
GOLINT_OPTIONS = --timeout 4m \
--build-tags "${MINIKUBE_INTEGRATION_BUILD_TAGS}" \
- --enable goimports,gocritic,golint,gocyclo,misspell,nakedret,stylecheck,unconvert,unparam \
+ --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
diff --git a/cmd/minikube/cmd/config/config.go b/cmd/minikube/cmd/config/config.go
index d76fe8a9f99f..dc572acf8990 100644
--- a/cmd/minikube/cmd/config/config.go
+++ b/cmd/minikube/cmd/config/config.go
@@ -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,
diff --git a/cmd/minikube/cmd/root.go b/cmd/minikube/cmd/root.go
index 4eded97c99c2..38f84246d9ed 100644
--- a/cmd/minikube/cmd/root.go
+++ b/cmd/minikube/cmd/root.go
@@ -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()
}
diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go
index 876175fdfa9e..84a97c5438f8 100644
--- a/cmd/minikube/cmd/start.go
+++ b/cmd/minikube/cmd/start.go
@@ -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"
@@ -194,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 %s)", driver.SupportedDrivers(), driver.Default()))
+ 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
@@ -289,6 +290,7 @@ func runStart(cmd *cobra.Command, args []string) {
}
driverName := selectDriver(oldConfig)
+ glog.Infof("selected: %v", driverName)
err = autoSetDriverOptions(cmd, driverName)
if err != nil {
glog.Errorf("Error autoSetOptions : %v", err)
@@ -297,11 +299,14 @@ func runStart(cmd *cobra.Command, args []string) {
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 := 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})
+ // 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)
@@ -541,17 +546,41 @@ func showKubectlInfo(kcs *kubeconfig.Settings, k8sVersion string) error {
func selectDriver(oldConfig *cfg.Config) string {
name := viper.GetString("vm-driver")
- // By default, the driver is whatever we used last time
+ glog.Infof("selectDriver: flag=%q, old=%v", name, oldConfig)
if name == "" {
- name = driver.Default()
+ // By default, the driver is whatever we used last time
if oldConfig != nil {
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})
}
+ 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 {
diff --git a/deploy/addons/gvisor/gvisor-pod.yaml.tmpl b/deploy/addons/gvisor/gvisor-pod.yaml.tmpl
index 652dbb681087..1b7d69cd84af 100644
--- a/deploy/addons/gvisor/gvisor-pod.yaml.tmpl
+++ b/deploy/addons/gvisor/gvisor-pod.yaml.tmpl
@@ -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
diff --git a/deploy/addons/layouts/gvisor/single.html b/deploy/addons/layouts/gvisor/single.html
new file mode 100644
index 000000000000..620f9d82b608
--- /dev/null
+++ b/deploy/addons/layouts/gvisor/single.html
@@ -0,0 +1,5 @@
+{{ define "main" }}
+
+ {{ .Render "content" }}
+
+{{ end }}
\ No newline at end of file
diff --git a/deploy/addons/layouts/helm-tiller/single.html b/deploy/addons/layouts/helm-tiller/single.html
new file mode 100644
index 000000000000..620f9d82b608
--- /dev/null
+++ b/deploy/addons/layouts/helm-tiller/single.html
@@ -0,0 +1,5 @@
+{{ define "main" }}
+
+ {{ .Render "content" }}
+
+{{ end }}
\ No newline at end of file
diff --git a/deploy/addons/layouts/ingress-dns/single.html b/deploy/addons/layouts/ingress-dns/single.html
new file mode 100644
index 000000000000..27fcd101d0d6
--- /dev/null
+++ b/deploy/addons/layouts/ingress-dns/single.html
@@ -0,0 +1,5 @@
+{{ define "main" }}
+
+ {{ .Render "content" }}
+
+{{ end }}
\ No newline at end of file
diff --git a/deploy/addons/layouts/storage-provisioner-gluster/single.html b/deploy/addons/layouts/storage-provisioner-gluster/single.html
new file mode 100644
index 000000000000..620f9d82b608
--- /dev/null
+++ b/deploy/addons/layouts/storage-provisioner-gluster/single.html
@@ -0,0 +1,5 @@
+{{ define "main" }}
+
+ {{ .Render "content" }}
+
+{{ end }}
\ No newline at end of file
diff --git a/deploy/gvisor/Dockerfile b/deploy/gvisor/Dockerfile
index 9dacfa546644..9d62239fc359 100644
--- a/deploy/gvisor/Dockerfile
+++ b/deploy/gvisor/Dockerfile
@@ -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"]
diff --git a/deploy/minikube/releases.json b/deploy/minikube/releases.json
index 33573e46b1c6..d9f6f0ea3804 100644
--- a/deploy/minikube/releases.json
+++ b/deploy/minikube/releases.json
@@ -1,4 +1,12 @@
[
+ {
+ "name": "v1.5.0",
+ "checksums": {
+ "darwin": "eb716c176f404bb555966ff3947d5d9c5fb63eb902d11c83839fda492ff4b1fc",
+ "linux": "ca50dcc7c83d4dde484d650a5a1934ea1bef692340af3aa831d34c6e847b2770",
+ "windows": "bdd61e446f49570428848ad15337264edfecc55d1dd4aed4499d559f9c8383b9"
+ }
+ },
{
"name": "v1.4.0",
"checksums": {
diff --git a/hack/boilerplate/boilerplate.go b/hack/boilerplate/boilerplate.go
new file mode 100644
index 000000000000..1318711f710b
--- /dev/null
+++ b/hack/boilerplate/boilerplate.go
@@ -0,0 +1,164 @@
+/*
+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
+}
diff --git a/hack/boilerplate/boilerplate.py b/hack/boilerplate/boilerplate.py
deleted file mode 100755
index 35fc425706cf..000000000000
--- a/hack/boilerplate/boilerplate.py
+++ /dev/null
@@ -1,170 +0,0 @@
-#!/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())
diff --git a/hack/boilerplate/fix.sh b/hack/boilerplate/fix.sh
index 4d01cb312c1c..b2b4c98b84a0 100755
--- a/hack/boilerplate/fix.sh
+++ b/hack/boilerplate/fix.sh
@@ -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)"
diff --git a/hack/jenkins/common.sh b/hack/jenkins/common.sh
index ccd921616037..fb4ae49338b4 100755
--- a/hack/jenkins/common.sh
+++ b/hack/jenkins/common.sh
@@ -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 ""
diff --git a/hack/jenkins/linux_integration_tests_kvm.sh b/hack/jenkins/linux_integration_tests_kvm.sh
index 5af0e48b3039..fe40576f65e4 100755
--- a/hack/jenkins/linux_integration_tests_kvm.sh
+++ b/hack/jenkins/linux_integration_tests_kvm.sh
@@ -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
diff --git a/hack/jenkins/linux_integration_tests_none.sh b/hack/jenkins/linux_integration_tests_none.sh
index 6721d15e2455..767e6867a09b 100755
--- a/hack/jenkins/linux_integration_tests_none.sh
+++ b/hack/jenkins/linux_integration_tests_none.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"
diff --git a/hack/jenkins/linux_integration_tests_virtualbox.sh b/hack/jenkins/linux_integration_tests_virtualbox.sh
index bd413c158687..6f624eeead0a 100755
--- a/hack/jenkins/linux_integration_tests_virtualbox.sh
+++ b/hack/jenkins/linux_integration_tests_virtualbox.sh
@@ -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
diff --git a/hack/jenkins/osx_integration_tests_hyperkit.sh b/hack/jenkins/osx_integration_tests_hyperkit.sh
index 7091d6512b0f..aa9d5d69d104 100755
--- a/hack/jenkins/osx_integration_tests_hyperkit.sh
+++ b/hack/jenkins/osx_integration_tests_hyperkit.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
diff --git a/hack/jenkins/osx_integration_tests_virtualbox.sh b/hack/jenkins/osx_integration_tests_virtualbox.sh
index cb48a389ed2a..8f7c6e3dd0b8 100755
--- a/hack/jenkins/osx_integration_tests_virtualbox.sh
+++ b/hack/jenkins/osx_integration_tests_virtualbox.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
diff --git a/hack/jenkins/windows_integration_test_hyperv.ps1 b/hack/jenkins/windows_integration_test_hyperv.ps1
index fb42370c4977..995b17506c52 100644
--- a/hack/jenkins/windows_integration_test_hyperv.ps1
+++ b/hack/jenkins/windows_integration_test_hyperv.ps1
@@ -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"}
diff --git a/hack/jenkins/windows_integration_test_virtualbox.ps1 b/hack/jenkins/windows_integration_test_virtualbox.ps1
index 559a6e220e1f..86dfde120a2c 100644
--- a/hack/jenkins/windows_integration_test_virtualbox.ps1
+++ b/hack/jenkins/windows_integration_test_virtualbox.ps1
@@ -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"}
diff --git a/netlify.toml b/netlify.toml
index 6084cd18c02d..d335d812befb 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -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"
diff --git a/pkg/gvisor/enable.go b/pkg/gvisor/enable.go
index 2a5f9e315a29..b2905574b878 100644
--- a/pkg/gvisor/enable.go
+++ b/pkg/gvisor/enable.go
@@ -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")
diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm_test.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm_test.go
index f6d696816dfb..e638c32c4532 100644
--- a/pkg/minikube/bootstrapper/kubeadm/kubeadm_test.go
+++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm_test.go
@@ -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]
`,
diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go
index f976b297de8d..3e1a4683f02a 100644
--- a/pkg/minikube/cluster/cluster.go
+++ b/pkg/minikube/cluster/cluster.go
@@ -433,15 +433,11 @@ 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/missing 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)
}
-
- dd := def.ConfigCreator(config)
+ dd := def.Config(config)
data, err := json.Marshal(dd)
if err != nil {
return nil, errors.Wrap(err, "marshal")
diff --git a/pkg/minikube/cluster/cluster_test.go b/pkg/minikube/cluster/cluster_test.go
index 62d7fd3f483f..ae2ee8c5b897 100644
--- a/pkg/minikube/cluster/cluster_test.go
+++ b/pkg/minikube/cluster/cluster_test.go
@@ -22,8 +22,8 @@ import (
"testing"
"time"
- // Register drivers
- _ "k8s.io/minikube/pkg/minikube/registry/drvs"
+ // Driver used by testdata
+ _ "k8s.io/minikube/pkg/minikube/registry/drvs/virtualbox"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/host"
@@ -47,18 +47,13 @@ func createMockDriverHost(c config.MachineConfig) interface{} {
func RegisterMockDriver(t *testing.T) {
t.Helper()
- _, err := registry.Driver(driver.Mock)
- // Already registered
- if err == nil {
+ if !registry.Driver(driver.Mock).Empty() {
return
}
- err = registry.Register(registry.DriverDef{
- Name: driver.Mock,
- 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)
@@ -103,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
@@ -111,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())
}
}
diff --git a/pkg/minikube/config/config_test.go b/pkg/minikube/config/config_test.go
index 9eef5a7a61cb..19671ef61788 100644
--- a/pkg/minikube/config/config_test.go
+++ b/pkg/minikube/config/config_test.go
@@ -22,8 +22,6 @@ import (
"os"
"reflect"
"testing"
-
- "k8s.io/minikube/pkg/minikube/driver"
)
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": driver.KVM2,
+ "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": driver.KVM2,
+ "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": driver.KVM2,
+ "vm-driver": "test-driver",
"cpus": 4,
"disk-size": "20g",
"show-libmachine-logs": true,
diff --git a/pkg/minikube/config/profile.go b/pkg/minikube/config/profile.go
index 55b933bc34a1..f07aad446b48 100644
--- a/pkg/minikube/config/profile.go
+++ b/pkg/minikube/config/profile.go
@@ -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) {
diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go
index af0244a8d43d..ba0aeacf106e 100644
--- a/pkg/minikube/constants/constants.go
+++ b/pkg/minikube/constants/constants.go
@@ -65,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"
diff --git a/pkg/minikube/driver/driver.go b/pkg/minikube/driver/driver.go
index 7d6712d8ea55..a87d7a607120 100644
--- a/pkg/minikube/driver/driver.go
+++ b/pkg/minikube/driver/driver.go
@@ -19,6 +19,10 @@ package driver
import (
"fmt"
"os"
+ "sort"
+
+ "github.com/golang/glog"
+ "k8s.io/minikube/pkg/minikube/registry"
)
const (
@@ -33,6 +37,11 @@ const (
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
@@ -62,14 +71,12 @@ type FlagHints struct {
// FlagDefaults returns suggested defaults based on a driver
func FlagDefaults(name string) FlagHints {
if name != None {
- return FlagHints{}
+ return FlagHints{CacheImages: true}
}
- // for more info see: https://github.com/kubernetes/minikube/issues/3511
- f := "/run/systemd/resolve/resolv.conf"
extraOpts := ""
- if _, err := os.Stat(f); err == nil {
- extraOpts = fmt.Sprintf("kubelet.resolv-conf=%s", f)
+ if _, err := os.Stat(systemdResolvConf); err == nil {
+ extraOpts = fmt.Sprintf("kubelet.resolv-conf=%s", systemdResolvConf)
}
return FlagHints{
ExtraOptions: extraOpts,
@@ -77,7 +84,50 @@ func FlagDefaults(name string) FlagHints {
}
}
-// Default returns the default driver on this hos
-func Default() string {
- return VirtualBox
+// 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)
}
diff --git a/pkg/minikube/driver/driver_test.go b/pkg/minikube/driver/driver_test.go
new file mode 100644
index 000000000000..cd35e8d77598
--- /dev/null
+++ b/pkg/minikube/driver/driver_test.go
@@ -0,0 +1,162 @@
+/*
+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)
+ }
+ })
+ }
+}
diff --git a/pkg/minikube/driver/install_test.go b/pkg/minikube/driver/install_test.go
new file mode 100644
index 000000000000..f57e1f541e3b
--- /dev/null
+++ b/pkg/minikube/driver/install_test.go
@@ -0,0 +1,45 @@
+/*
+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)
+ }
+}
diff --git a/pkg/minikube/machine/client.go b/pkg/minikube/machine/client.go
index 2c6464b430fb..dd10ee31c9b6 100644
--- a/pkg/minikube/machine/client.go
+++ b/pkg/minikube/machine/client.go
@@ -19,6 +19,7 @@ package machine
import (
"crypto/tls"
"encoding/json"
+ "fmt"
"net"
"os"
"path/filepath"
@@ -81,17 +82,15 @@ type LocalClient struct {
// NewHost creates a new Host
func (api *LocalClient) NewHost(drvName string, rawDriver []byte) (*host.Host, error) {
- var def registry.DriverDef
- var err error
- if def, err = registry.Driver(drvName); err != nil {
- return nil, err
- } else if !def.Builtin || def.DriverCreator == nil {
+ def := registry.Driver(drvName)
+ if def.Empty() {
+ return nil, fmt.Errorf("driver %q does not exist", drvName)
+ }
+ if def.Init == nil {
return api.legacyClient.NewHost(drvName, rawDriver)
}
-
- d := def.DriverCreator()
-
- err = json.Unmarshal(rawDriver, d)
+ d := def.Init()
+ err := json.Unmarshal(rawDriver, d)
if err != nil {
return nil, errors.Wrapf(err, "Error getting driver %s", string(rawDriver))
}
@@ -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)
}
@@ -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)
}
@@ -271,12 +272,9 @@ func (cg *CertGenerator) ValidateCertificate(addr string, authOptions *auth.Opti
}
func registerDriver(drvName string) {
- def, err := registry.Driver(drvName)
- if err != nil {
- if err == registry.ErrDriverNotFound {
- exit.UsageT("unsupported or missing driver: {{.name}}", out.V{"name": drvName})
- }
- exit.WithError("error getting driver", err)
+ 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())
}
diff --git a/pkg/minikube/out/style.go b/pkg/minikube/out/style.go
index 4791787413b6..0af52ed464d1 100644
--- a/pkg/minikube/out/style.go
+++ b/pkg/minikube/out/style.go
@@ -81,6 +81,7 @@ var styles = map[StyleEnum]style{
Check: {Prefix: "✅ "},
Celebration: {Prefix: "🎉 "},
Workaround: {Prefix: "👉 ", LowPrefix: lowIndent},
+ Sparkle: {Prefix: "✨ "},
// Specialized purpose styles
ISODownload: {Prefix: "💿 "},
diff --git a/pkg/minikube/out/style_enum.go b/pkg/minikube/out/style_enum.go
index 890c54f6b001..0bc8ac182279 100644
--- a/pkg/minikube/out/style_enum.go
+++ b/pkg/minikube/out/style_enum.go
@@ -83,4 +83,5 @@ const (
Fileserver
Empty
Workaround
+ Sparkle
)
diff --git a/pkg/minikube/registry/drvs/hyperkit/driver.go b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go
similarity index 68%
rename from pkg/minikube/registry/drvs/hyperkit/driver.go
rename to pkg/minikube/registry/drvs/hyperkit/hyperkit.go
index c9c2f9369841..e42b4207dafe 100644
--- a/pkg/minikube/registry/drvs/hyperkit/driver.go
+++ b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go
@@ -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/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
- "k8s.io/minikube/pkg/minikube/driver"
+)
+
+const (
+ docURL = "https://minikube.sigs.k8s.io/docs/reference/drivers/hyperkit/"
)
func init() {
if err := registry.Register(registry.DriverDef{
- Name: driver.HyperKit,
- 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}
+}
diff --git a/pkg/minikube/registry/drvs/hyperv/driver.go b/pkg/minikube/registry/drvs/hyperv/hyperv.go
similarity index 55%
rename from pkg/minikube/registry/drvs/hyperv/driver.go
rename to pkg/minikube/registry/drvs/hyperv/hyperv.go
index 50dc236607bd..e0216f12cfe8 100644
--- a/pkg/minikube/registry/drvs/hyperv/driver.go
+++ b/pkg/minikube/registry/drvs/hyperv/hyperv.go
@@ -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/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: driver.HyperV,
- 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}
+}
diff --git a/pkg/minikube/registry/drvs/kvm2/driver.go b/pkg/minikube/registry/drvs/kvm2/kvm2.go
similarity index 59%
rename from pkg/minikube/registry/drvs/kvm2/driver.go
rename to pkg/minikube/registry/drvs/kvm2/kvm2.go
index 7d14ed952ea7..cdd61f20945e 100644
--- a/pkg/minikube/registry/drvs/kvm2/driver.go
+++ b/pkg/minikube/registry/drvs/kvm2/kvm2.go
@@ -20,27 +20,34 @@ package kvm2
import (
"fmt"
+ "os/exec"
"path/filepath"
+ "strings"
"github.com/docker/machine/libmachine/drivers"
+
"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: driver.KVM2,
- 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,9 +64,9 @@ type kvmDriver struct {
ConnectionURI string
}
-func createKVM2Host(mc config.MachineConfig) interface{} {
+func configure(mc config.MachineConfig) interface{} {
name := config.GetMachineName()
- return &kvmDriver{
+ return kvmDriver{
BaseDriver: &drivers.BaseDriver{
MachineName: name,
StorePath: localpath.MiniPath(),
@@ -78,3 +85,33 @@ func createKVM2Host(mc config.MachineConfig) interface{} {
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}
+}
diff --git a/pkg/minikube/registry/drvs/none/driver.go b/pkg/minikube/registry/drvs/none/none.go
similarity index 67%
rename from pkg/minikube/registry/drvs/none/driver.go
rename to pkg/minikube/registry/drvs/none/none.go
index 119a7439374a..fa094f9aeaa8 100644
--- a/pkg/minikube/registry/drvs/none/driver.go
+++ b/pkg/minikube/registry/drvs/none/none.go
@@ -1,3 +1,5 @@
+// +build linux
+
/*
Copyright 2018 The Kubernetes Authors All rights reserved.
@@ -18,6 +20,7 @@ package none
import (
"fmt"
+ "os/exec"
"github.com/docker/machine/libmachine/drivers"
"k8s.io/minikube/pkg/drivers/none"
@@ -29,22 +32,28 @@ import (
func init() {
if err := registry.Register(registry.DriverDef{
- Name: driver.None,
- 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(mc config.MachineConfig) interface{} {
+func configure(mc config.MachineConfig) interface{} {
return none.NewDriver(none.Config{
MachineName: config.GetMachineName(),
StorePath: localpath.MiniPath(),
ContainerRuntime: mc.ContainerRuntime,
})
}
+
+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 registry.State{Installed: true, Healthy: true}
+}
diff --git a/pkg/minikube/registry/drvs/parallels/driver.go b/pkg/minikube/registry/drvs/parallels/parallels.go
similarity index 69%
rename from pkg/minikube/registry/drvs/parallels/driver.go
rename to pkg/minikube/registry/drvs/parallels/parallels.go
index f0648fb6a821..193ea54da9d9 100644
--- a/pkg/minikube/registry/drvs/parallels/driver.go
+++ b/pkg/minikube/registry/drvs/parallels/parallels.go
@@ -20,6 +20,7 @@ package parallels
import (
"fmt"
+ "os/exec"
parallels "github.com/Parallels/docker-machine-parallels"
"github.com/docker/machine/libmachine/drivers"
@@ -31,12 +32,11 @@ import (
func init() {
err := registry.Register(registry.DriverDef{
- Name: driver.Parallels,
- 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}
+}
diff --git a/pkg/minikube/registry/drvs/virtualbox/doc.go b/pkg/minikube/registry/drvs/virtualbox/doc.go
deleted file mode 100644
index 0e6eff9e8ca1..000000000000
--- a/pkg/minikube/registry/drvs/virtualbox/doc.go
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-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
diff --git a/pkg/minikube/registry/drvs/virtualbox/driver.go b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go
similarity index 57%
rename from pkg/minikube/registry/drvs/virtualbox/driver.go
rename to pkg/minikube/registry/drvs/virtualbox/virtualbox.go
index 5677ec614631..fa4483cf0b3c 100644
--- a/pkg/minikube/registry/drvs/virtualbox/driver.go
+++ b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go
@@ -18,34 +18,38 @@ package virtualbox
import (
"fmt"
+ "os/exec"
+ "strings"
"github.com/docker/machine/drivers/virtualbox"
"github.com/docker/machine/libmachine/drivers"
+
"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: driver.VirtualBox,
- 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(mc config.MachineConfig) interface{} {
+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
@@ -57,6 +61,31 @@ func createVirtualboxHost(mc config.MachineConfig) interface{} {
d.HostOnlyNicType = defaultVirtualboxNicType
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}
+}
diff --git a/pkg/minikube/registry/drvs/vmware/driver.go b/pkg/minikube/registry/drvs/vmware/vmware.go
similarity index 67%
rename from pkg/minikube/registry/drvs/vmware/driver.go
rename to pkg/minikube/registry/drvs/vmware/vmware.go
index 10b53ca390bc..82b1126d1838 100644
--- a/pkg/minikube/registry/drvs/vmware/driver.go
+++ b/pkg/minikube/registry/drvs/vmware/vmware.go
@@ -18,6 +18,7 @@ package vmware
import (
"fmt"
+ "os/exec"
vmwcfg "github.com/machine-drivers/docker-machine-driver-vmware/pkg/drivers/vmware/config"
"k8s.io/minikube/pkg/minikube/config"
@@ -28,16 +29,17 @@ import (
func init() {
err := registry.Register(registry.DriverDef{
- Name: driver.VMware,
- 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(mc config.MachineConfig) interface{} {
+func configure(mc config.MachineConfig) interface{} {
d := vmwcfg.NewConfig(config.GetMachineName(), localpath.MiniPath())
d.Boot2DockerURL = mc.Downloader.GetISOFileURI(mc.MinikubeISO)
d.Memory = mc.Memory
@@ -49,3 +51,15 @@ func createVMwareHost(mc config.MachineConfig) interface{} {
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}
+}
diff --git a/pkg/minikube/registry/drvs/vmwarefusion/driver.go b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go
similarity index 70%
rename from pkg/minikube/registry/drvs/vmwarefusion/driver.go
rename to pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go
index 7cb0893818f1..cbff0022ed0f 100644
--- a/pkg/minikube/registry/drvs/vmwarefusion/driver.go
+++ b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go
@@ -20,30 +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/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/registry"
- "k8s.io/minikube/pkg/minikube/driver"
-
)
func init() {
if err := registry.Register(registry.DriverDef{
- Name: driver.VMwareFusion,
- 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
@@ -55,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}
+}
diff --git a/pkg/minikube/registry/global.go b/pkg/minikube/registry/global.go
new file mode 100644
index 000000000000..97882296a540
--- /dev/null
+++ b/pkg/minikube/registry/global.go
@@ -0,0 +1,85 @@
+/*
+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()
+}
diff --git a/pkg/minikube/registry/global_test.go b/pkg/minikube/registry/global_test.go
new file mode 100644
index 000000000000..1ccb418a9145
--- /dev/null
+++ b/pkg/minikube/registry/global_test.go
@@ -0,0 +1,118 @@
+/*
+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)
+ }
+}
diff --git a/pkg/minikube/registry/registry.go b/pkg/minikube/registry/registry.go
index 15b7b15e41e9..9fd491ea9e97 100644
--- a/pkg/minikube/registry/registry.go
+++ b/pkg/minikube/registry/registry.go
@@ -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]
}
diff --git a/pkg/minikube/registry/registry_test.go b/pkg/minikube/registry/registry_test.go
index 8d44019a08a8..e1d84b25efae 100644
--- a/pkg/minikube/registry/registry_test.go
+++ b/pkg/minikube/registry/registry_test.go
@@ -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) {
- name := "foo"
- d, err := registry.Driver(name)
- if err != nil {
- t.Fatalf("expect nil for registering foo driver, but got: %v", err)
- }
- if d.Name != name {
- t.Fatalf("expect registry.Driver(%s) returns registered driver, but got: %s", name, d.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)
- }
- })
}
diff --git a/site/config.toml b/site/config.toml
index e49df4aedd17..bdebbf905173 100644
--- a/site/config.toml
+++ b/site/config.toml
@@ -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 = ""
diff --git a/site/content/en/docs/Examples/_index.md b/site/content/en/docs/Examples/_index.md
index 84092b2cb4dd..a72b1c0ade47 100755
--- a/site/content/en/docs/Examples/_index.md
+++ b/site/content/en/docs/Examples/_index.md
@@ -39,3 +39,7 @@ Stop your local cluster:
Delete your local cluster:
`minikube delete`
+
+Delete all local clusters and profiles
+
+`minikube delete --all`
diff --git a/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc b/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc
index bb67f88d293d..6bce73731acf 100644
--- a/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc
+++ b/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc
@@ -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
diff --git a/site/content/en/docs/Tasks/addons.md b/site/content/en/docs/Tasks/addons.md
index c454360cbcc0..b29499a8fbac 100644
--- a/site/content/en/docs/Tasks/addons.md
+++ b/site/content/en/docs/Tasks/addons.md
@@ -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
diff --git a/test.sh b/test.sh
index c48b4a1ef055..846ed3e5752c 100755
--- a/test.sh
+++ b/test.sh
@@ -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
diff --git a/test/integration/README.md b/test/integration/README.md
index 1a554492f678..7af031f6eab7 100644
--- a/test/integration/README.md
+++ b/test/integration/README.md
@@ -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.
diff --git a/test/integration/Untitled-1 b/test/integration/Untitled-1
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/test/integration/a_serial_tests.go b/test/integration/a_serial_test.go
similarity index 52%
rename from test/integration/a_serial_tests.go
rename to test/integration/a_serial_test.go
index 7e4b604efff2..ae931662d707 100644
--- a/test/integration/a_serial_tests.go
+++ b/test/integration/a_serial_test.go
@@ -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)
diff --git a/test/integration/gvisor_addon_test.go b/test/integration/gvisor_addon_test.go
index c5e2790bb6b0..b75aa0bbb1b2 100644
--- a/test/integration/gvisor_addon_test.go
+++ b/test/integration/gvisor_addon_test.go
@@ -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
diff --git a/test/integration/main.go b/test/integration/main.go
index 02ce476cf9db..dbd5830c156b 100644
--- a/test/integration/main.go
+++ b/test/integration/main.go
@@ -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
+}