Rebased on master

pull/5757/head
Priya Wadhwa 2019-10-28 10:46:35 -07:00
commit f92b308f9a
61 changed files with 1256 additions and 572 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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()
}

View File

@ -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 {

View File

@ -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

View File

@ -0,0 +1,5 @@
{{ define "main" }}
<div style="padding-top:20px">
{{ .Render "content" }}
</div>
{{ end }}

View File

@ -0,0 +1,5 @@
{{ define "main" }}
<div style="padding-top:20px">
{{ .Render "content" }}
</div>
{{ end }}

View File

@ -0,0 +1,5 @@
{{ define "main" }}
<div style="padding-top:60px">
{{ .Render "content" }}
</div>
{{ end }}

View File

@ -0,0 +1,5 @@
{{ define "main" }}
<div style="padding-top:20px">
{{ .Render "content" }}
</div>
{{ end }}

View File

@ -12,9 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM ubuntu:18.04
RUN apt-get update && \
apt-get install -y kmod gcc wget xz-utils libc6-dev bc libelf-dev bison flex openssl libssl-dev libidn2-0 sudo libcap2 && \
rm -rf /var/lib/apt/lists/*
# Need an image with chroot
FROM alpine:3
COPY out/gvisor-addon /gvisor-addon
CMD ["/gvisor-addon"]

View File

@ -1,4 +1,12 @@
[
{
"name": "v1.5.0",
"checksums": {
"darwin": "eb716c176f404bb555966ff3947d5d9c5fb63eb902d11c83839fda492ff4b1fc",
"linux": "ca50dcc7c83d4dde484d650a5a1934ea1bef692340af3aa831d34c6e847b2770",
"windows": "bdd61e446f49570428848ad15337264edfecc55d1dd4aed4499d559f9c8383b9"
}
},
{
"name": "v1.4.0",
"checksums": {

View File

@ -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
}

View File

@ -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())

View File

@ -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)"

View File

@ -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 ""

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"}

View File

@ -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"}

View File

@ -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"

View File

@ -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")

View File

@ -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]
`,

View File

@ -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")

View File

@ -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())
}
}

View File

@ -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,

View File

@ -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) {

View File

@ -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"

View File

@ -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)
}

View File

@ -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)
}
})
}
}

View File

@ -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)
}
}

View File

@ -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())
}

View File

@ -81,6 +81,7 @@ var styles = map[StyleEnum]style{
Check: {Prefix: "✅ "},
Celebration: {Prefix: "🎉 "},
Workaround: {Prefix: "👉 ", LowPrefix: lowIndent},
Sparkle: {Prefix: "✨ "},
// Specialized purpose styles
ISODownload: {Prefix: "💿 "},

View File

@ -83,4 +83,5 @@ const (
Fileserver
Empty
Workaround
Sparkle
)

View File

@ -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}
}

View File

@ -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}
}

View File

@ -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}
}

View File

@ -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}
}

View File

@ -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}
}

View File

@ -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

View File

@ -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}
}

View File

@ -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}
}

View File

@ -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}
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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")
// Priority is how we determine what driver to default to
type Priority int
// ErrDriverNotFound is the error returned when driver of a given name does
// not exist in registry
ErrDriverNotFound = errors.New("registry: driver not found")
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{}
// DriverFactory is a function that loads a byte stream and creates a driver.
type DriverFactory func() drivers.Driver
// Loader is a function that loads a byte stream and creates a driver.
type Loader func() drivers.Driver
// DriverDef defines a machine driver metadata. It tells minikube how to initialize
// and load drivers.
// 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 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]
}

View File

@ -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)
}
d := r.Driver("foo")
if d.Empty() {
t.Errorf("driver.Empty = true, expected false")
}
d = r.Driver("bar")
if !d.Empty() {
t.Errorf("driver.Empty = false, expected true")
}
}
func TestRegistry1(t *testing.T) {
foo := testDriver("foo")
bar := testDriver("bar")
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)
}
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))
}
})
}
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)
}
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")
}
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)
}
})
if diff := cmp.Diff(r.List(), []DriverDef{foo}); diff != "" {
t.Errorf("list mismatch (-want +got):\n%s", diff)
}
}

View File

@ -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 = ""

View File

@ -39,3 +39,7 @@ Stop your local cluster:
Delete your local cluster:
`minikube delete`
Delete all local clusters and profiles
`minikube delete --all`

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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
}