Merge master

pull/5032/head
Thomas Stromberg 2019-08-21 10:26:10 -07:00
commit 62a452edab
50 changed files with 463 additions and 332 deletions

View File

@ -5,7 +5,7 @@ env:
- GOPROXY=https://proxy.golang.org - GOPROXY=https://proxy.golang.org
matrix: matrix:
include: include:
- go: 1.12.7 - go: 1.12.9
- language: python - language: python
before_install: pip install flake8 before_install: pip install flake8
script: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics script: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics

View File

@ -22,6 +22,9 @@ ISO_VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).0
VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD) VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD)
DEB_VERSION ?= $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD) DEB_VERSION ?= $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD)
RPM_VERSION ?= $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD) RPM_VERSION ?= $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD)
# used by hack/jenkins/release_build_and_upload.sh and KVM_BUILD_IMAGE, see also BUILD_IMAGE below
GO_VERSION ?= 1.12.9
INSTALL_SIZE ?= $(shell du out/minikube-windows-amd64.exe | cut -f1) INSTALL_SIZE ?= $(shell du out/minikube-windows-amd64.exe | cut -f1)
BUILDROOT_BRANCH ?= 2018.05.3 BUILDROOT_BRANCH ?= 2018.05.3
REGISTRY?=gcr.io/k8s-minikube REGISTRY?=gcr.io/k8s-minikube
@ -31,8 +34,8 @@ COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true)
COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}") COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}")
HYPERKIT_BUILD_IMAGE ?= karalabe/xgo-1.12.x HYPERKIT_BUILD_IMAGE ?= karalabe/xgo-1.12.x
# NOTE: "latest" as of 2019-07-12. kube-cross images aren't updated as often as Kubernetes # NOTE: "latest" as of 2019-08-15. kube-cross images aren't updated as often as Kubernetes
BUILD_IMAGE ?= k8s.gcr.io/kube-cross:v1.12.7-1 BUILD_IMAGE ?= k8s.gcr.io/kube-cross:v$(GO_VERSION)-1
ISO_BUILD_IMAGE ?= $(REGISTRY)/buildroot-image ISO_BUILD_IMAGE ?= $(REGISTRY)/buildroot-image
KVM_BUILD_IMAGE ?= $(REGISTRY)/kvm-build-image:$(GO_VERSION) KVM_BUILD_IMAGE ?= $(REGISTRY)/kvm-build-image:$(GO_VERSION)
@ -44,10 +47,7 @@ MINIKUBE_UPLOAD_LOCATION := gs://${MINIKUBE_BUCKET}
MINIKUBE_RELEASES_URL=https://github.com/kubernetes/minikube/releases/download MINIKUBE_RELEASES_URL=https://github.com/kubernetes/minikube/releases/download
KERNEL_VERSION ?= 4.15 KERNEL_VERSION ?= 4.15
# latest from https://github.com/golangci/golangci-lint/releases
# Currently *only* used for the KVM_BUILD_IMAGE, see also BUILD_IMAGE above
GO_VERSION ?= 1.12.7
GOLINT_VERSION ?= v1.17.1 GOLINT_VERSION ?= v1.17.1
# Limit number of default jobs, to avoid the CI builds running out of memory # Limit number of default jobs, to avoid the CI builds running out of memory
GOLINT_JOBS ?= 4 GOLINT_JOBS ?= 4
@ -101,7 +101,7 @@ SOURCE_DIRS = $(CMD_SOURCE_DIRS) test
SOURCE_PACKAGES = ./cmd/... ./pkg/... ./test/... SOURCE_PACKAGES = ./cmd/... ./pkg/... ./test/...
# kvm2 ldflags # kvm2 ldflags
KVM2_LDFLAGS := -X k8s.io/minikube/pkg/drivers/kvm.version=$(VERSION) -X k8s.io/minikube/pkg/drivers/kvm.gitCommitID=$(COMMIT) KVM2_LDFLAGS := -X k8s.io/minikube/pkg/drivers/kvm.version=$(VERSION) -X k8s.io/minikube/pkg/drivers/kvm.gitCommitID=$(COMMIT)
# hyperkit ldflags # hyperkit ldflags
HYPERKIT_LDFLAGS := -X k8s.io/minikube/pkg/drivers/hyperkit.version=$(VERSION) -X k8s.io/minikube/pkg/drivers/hyperkit.gitCommitID=$(COMMIT) HYPERKIT_LDFLAGS := -X k8s.io/minikube/pkg/drivers/hyperkit.version=$(VERSION) -X k8s.io/minikube/pkg/drivers/hyperkit.gitCommitID=$(COMMIT)

View File

@ -55,7 +55,7 @@ minikube is a Kubernetes [#sig-cluster-lifecycle](https://github.com/kubernetes/
* [**#minikube on Kubernetes Slack**](https://kubernetes.slack.com) - Live chat with minikube developers! * [**#minikube on Kubernetes Slack**](https://kubernetes.slack.com) - Live chat with minikube developers!
* [minikube-users mailing list](https://groups.google.com/forum/#!forum/minikube-users) * [minikube-users mailing list](https://groups.google.com/forum/#!forum/minikube-users)
* [minikube-dev mailing list](https://groups.google.com/forum/#!forum/minikube-dev) * [minikube-dev mailing list](https://groups.google.com/forum/#!forum/minikube-dev)
* [Bi-weekly office hours, Mondays @ 10am PST](https://tinyurl.com/minikube-oh) * [Bi-weekly office hours, Mondays @ 11am PST](https://tinyurl.com/minikube-oh)
* [Contributing](https://minikube.sigs.k8s.io/docs/contributing/) * [Contributing](https://minikube.sigs.k8s.io/docs/contributing/)
* [Development Roadmap](https://minikube.sigs.k8s.io/docs/contributing/roadmap/) * [Development Roadmap](https://minikube.sigs.k8s.io/docs/contributing/roadmap/)

View File

@ -67,7 +67,7 @@ var deleteCacheCmd = &cobra.Command{
} }
func imagesInConfigFile() ([]string, error) { func imagesInConfigFile() ([]string, error) {
configFile, err := config.ReadConfig() configFile, err := config.ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -290,7 +290,7 @@ func configurableFields() string {
// ListConfigMap list entries from config file // ListConfigMap list entries from config file
func ListConfigMap(name string) ([]string, error) { func ListConfigMap(name string) ([]string, error) {
configFile, err := config.ReadConfig() configFile, err := config.ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -310,7 +310,7 @@ func AddToConfigMap(name string, images []string) error {
return err return err
} }
// Set the values // Set the values
cfg, err := config.ReadConfig() cfg, err := config.ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return err return err
} }
@ -337,7 +337,7 @@ func DeleteFromConfigMap(name string, images []string) error {
return err return err
} }
// Set the values // Set the values
cfg, err := config.ReadConfig() cfg, err := config.ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return err return err
} }

View File

@ -56,7 +56,7 @@ func Set(name string, value string) error {
} }
// Set the value // Set the value
config, err := pkgConfig.ReadConfig() config, err := pkgConfig.ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return err return err
} }

View File

@ -44,7 +44,7 @@ func init() {
// Unset unsets a property // Unset unsets a property
func Unset(name string) error { func Unset(name string) error {
m, err := pkgConfig.ReadConfig() m, err := pkgConfig.ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return err return err
} }

View File

@ -55,7 +55,7 @@ For the list of accessible variables for the template, see the struct values her
// View displays the current config // View displays the current config
func View() error { func View() error {
cfg, err := config.ReadConfig() cfg, err := config.ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return err return err
} }

View File

@ -63,7 +63,7 @@ func runDelete(cmd *cobra.Command, args []string) {
cc, err := pkg_config.Load() cc, err := pkg_config.Load()
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
out.ErrT(out.Sad, "Error loading profile config: {{.error}}", out.V{"name": profile}) out.ErrT(out.Sad, "Error loading profile {{.name}}: {{.error}}", out.V{"name": profile, "error": err})
} }
// In the case of "none", we want to uninstall Kubernetes as there is no VM to delete // In the case of "none", we want to uninstall Kubernetes as there is no VM to delete
@ -71,27 +71,38 @@ func runDelete(cmd *cobra.Command, args []string) {
uninstallKubernetes(api, cc.KubernetesConfig, viper.GetString(cmdcfg.Bootstrapper)) uninstallKubernetes(api, cc.KubernetesConfig, viper.GetString(cmdcfg.Bootstrapper))
} }
if err := killMountProcess(); err != nil {
out.T(out.FailureType, "Failed to kill mount process: {{.error}}", out.V{"error": err})
}
if err = cluster.DeleteHost(api); err != nil { if err = cluster.DeleteHost(api); err != nil {
switch err := errors.Cause(err).(type) { switch errors.Cause(err).(type) {
case mcnerror.ErrHostDoesNotExist: case mcnerror.ErrHostDoesNotExist:
out.T(out.Meh, `"{{.name}}" cluster does not exist`, out.V{"name": profile}) out.T(out.Meh, `"{{.name}}" cluster does not exist`, out.V{"name": profile})
default: default:
exit.WithError("Failed to delete cluster", err) out.T(out.FailureType, "Failed to delete cluster: {{.error}}", out.V{"error": err})
out.T(out.Notice, `You may need to manually remove the "{{.name}}" VM from your hypervisor`, out.V{"name": profile})
} }
} }
if err := killMountProcess(); err != nil { // In case DeleteHost didn't complete the job.
out.FatalT("Failed to kill mount process: {{.error}}", out.V{"error": err}) machineDir := filepath.Join(constants.GetMinipath(), "machines", profile)
if _, err := os.Stat(machineDir); err == nil {
out.T(out.DeletingHost, `Removing {{.directory}} ...`, out.V{"directory": machineDir})
err := os.RemoveAll(machineDir)
if err != nil {
exit.WithError("Unable to remove machine directory: %v", err)
}
} }
if err := pkg_config.DeleteProfile(viper.GetString(pkg_config.MachineProfile)); err != nil { if err := pkg_config.DeleteProfile(profile); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
out.T(out.Meh, `"{{.profile_name}}" profile does not exist`, out.V{"profile_name": profile}) out.T(out.Meh, `"{{.name}}" profile does not exist`, out.V{"name": profile})
os.Exit(0) os.Exit(0)
} }
exit.WithError("Failed to remove profile", err) exit.WithError("Failed to remove profile", err)
} }
out.T(out.Crushed, `The "{{.cluster_name}}" cluster has been deleted.`, out.V{"cluster_name": profile}) out.T(out.Crushed, `The "{{.name}}" cluster has been deleted.`, out.V{"name": profile})
machineName := pkg_config.GetMachineName() machineName := pkg_config.GetMachineName()
if err := kubeconfig.DeleteContext(constants.KubeconfigPath, machineName); err != nil { if err := kubeconfig.DeleteContext(constants.KubeconfigPath, machineName); err != nil {

View File

@ -102,6 +102,7 @@ const (
dnsProxy = "dns-proxy" dnsProxy = "dns-proxy"
hostDNSResolver = "host-dns-resolver" hostDNSResolver = "host-dns-resolver"
waitUntilHealthy = "wait" waitUntilHealthy = "wait"
waitTimeout = "wait-timeout"
) )
var ( var (
@ -111,7 +112,7 @@ var (
insecureRegistry []string insecureRegistry []string
apiServerNames []string apiServerNames []string
apiServerIPs []net.IP apiServerIPs []net.IP
extraOptions pkgutil.ExtraOptionSlice extraOptions cfg.ExtraOptionSlice
) )
func init() { func init() {
@ -148,6 +149,7 @@ func initMinikubeFlags() {
startCmd.Flags().String(networkPlugin, "", "The name of the network plugin.") startCmd.Flags().String(networkPlugin, "", "The name of the network plugin.")
startCmd.Flags().Bool(enableDefaultCNI, false, "Enable the default CNI plugin (/etc/cni/net.d/k8s.conf). Used in conjunction with \"--network-plugin=cni\".") startCmd.Flags().Bool(enableDefaultCNI, false, "Enable the default CNI plugin (/etc/cni/net.d/k8s.conf). Used in conjunction with \"--network-plugin=cni\".")
startCmd.Flags().Bool(waitUntilHealthy, true, "Wait until Kubernetes core services are healthy before exiting.") startCmd.Flags().Bool(waitUntilHealthy, true, "Wait until Kubernetes core services are healthy before exiting.")
startCmd.Flags().Duration(waitTimeout, 3*time.Minute, "max time to wait per Kubernetes core services to be healthy.")
} }
// initKubernetesFlags inits the commandline flags for kubernetes related options // initKubernetesFlags inits the commandline flags for kubernetes related options
@ -321,7 +323,7 @@ func runStart(cmd *cobra.Command, args []string) {
// special ops for none driver, like change minikube directory. // special ops for none driver, like change minikube directory.
prepareNone(viper.GetString(vmDriver)) prepareNone(viper.GetString(vmDriver))
if viper.GetBool(waitUntilHealthy) { if viper.GetBool(waitUntilHealthy) {
if err := bs.WaitCluster(config.KubernetesConfig); err != nil { if err := bs.WaitCluster(config.KubernetesConfig, viper.GetDuration(waitTimeout)); err != nil {
exit.WithError("Wait failed", err) exit.WithError("Wait failed", err)
} }
} }
@ -538,8 +540,8 @@ func validateConfig() {
// check that kubeadm extra args contain only whitelisted parameters // check that kubeadm extra args contain only whitelisted parameters
for param := range extraOptions.AsMap().Get(kubeadm.Kubeadm) { for param := range extraOptions.AsMap().Get(kubeadm.Kubeadm) {
if !pkgutil.ContainsString(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmCmdParam], param) && if !cfg.ContainsParam(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmCmdParam], param) &&
!pkgutil.ContainsString(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmConfigParam], param) { !cfg.ContainsParam(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmConfigParam], param) {
exit.UsageT("Sorry, the kubeadm.{{.parameter_name}} parameter is currently not supported by --extra-config", out.V{"parameter_name": param}) exit.UsageT("Sorry, the kubeadm.{{.parameter_name}} parameter is currently not supported by --extra-config", out.V{"parameter_name": param})
} }
} }

View File

@ -1,5 +1,5 @@
## storage-provisioner-gluster addon ## storage-provisioner-gluster addon
[Gluster](https://gluster.org/), a scalable network filesystem that provides dynamic provisioning of PersistenVolumeClaims. [Gluster](https://gluster.org/), a scalable network filesystem that provides dynamic provisioning of PersistentVolumeClaims.
### Starting Minikube ### Starting Minikube
This addon works within Minikube, without any additional configuration. This addon works within Minikube, without any additional configuration.

View File

@ -71,11 +71,12 @@ echo ">> Downloading test inputs from ${MINIKUBE_LOCATION} ..."
gsutil -qm cp \ gsutil -qm cp \
"gs://minikube-builds/${MINIKUBE_LOCATION}/minikube-${OS_ARCH}" \ "gs://minikube-builds/${MINIKUBE_LOCATION}/minikube-${OS_ARCH}" \
"gs://minikube-builds/${MINIKUBE_LOCATION}/docker-machine-driver"-* \ "gs://minikube-builds/${MINIKUBE_LOCATION}/docker-machine-driver"-* \
"gs://minikube-builds/${MINIKUBE_LOCATION}/e2e-${OS_ARCH}" \ "gs://minikube-builds/${MINIKUBE_LOCATION}/e2e-${OS_ARCH}" out
"gs://minikube-builds/${MINIKUBE_LOCATION}/gvisor-addon" out
gsutil -qm cp "gs://minikube-builds/${MINIKUBE_LOCATION}/testdata"/* testdata/ gsutil -qm cp "gs://minikube-builds/${MINIKUBE_LOCATION}/testdata"/* testdata/
gsutil -qm cp "gs://minikube-builds/${MINIKUBE_LOCATION}/gvisor-addon" testdata/
# Set the executable bit on the e2e binary and out binary # Set the executable bit on the e2e binary and out binary
export MINIKUBE_BIN="out/minikube-${OS_ARCH}" export MINIKUBE_BIN="out/minikube-${OS_ARCH}"
@ -125,6 +126,18 @@ for stale_dir in ${TEST_ROOT}/*; do
rmdir "${stale_dir}" || true rmdir "${stale_dir}" || true
done done
# sometimes tests left over zombie procs that won't exit
# for example:
# jenkins 20041 0.0 0.0 0 0 ? Z Aug19 0:00 [minikube-linux-] <defunct>
zombie_defuncts=$(ps -A -ostat,ppid | awk '/[zZ]/ && !a[$2]++ {print $2}')
if [[ "${zombie_defuncts}" != "" ]]; then
echo "Found zombie defunct procs to kill..."
ps -f -p ${zombie_defuncts} || true
sudo -E kill ${zombie_defuncts} || true
fi
if type -P virsh; then if type -P virsh; then
virsh -c qemu:///system list --all virsh -c qemu:///system list --all
virsh -c qemu:///system list --all \ virsh -c qemu:///system list --all \
@ -165,6 +178,7 @@ if type -P vboxmanage; then
vboxmanage list vms || true vboxmanage list vms || true
fi fi
if type -P hdiutil; then if type -P hdiutil; then
hdiutil info | grep -E "/dev/disk[1-9][^s]" || true hdiutil info | grep -E "/dev/disk[1-9][^s]" || true
hdiutil info \ hdiutil info \
@ -198,6 +212,14 @@ if [[ "${VM_DRIVER}" == "hyperkit" ]]; then
fi fi
fi fi
vboxprocs=$(pgrep VBox || true)
if [[ "${vboxprocs}" != "" ]]; then
echo "error: killing left over virtualbox processes ..."
ps -f -p ${vboxprocs} || true
sudo -E kill ${vboxprocs} || true
fi
kprocs=$(pgrep kubectl || true) kprocs=$(pgrep kubectl || true)
if [[ "${kprocs}" != "" ]]; then if [[ "${kprocs}" != "" ]]; then
echo "error: killing hung kubectl processes ..." echo "error: killing hung kubectl processes ..."
@ -241,6 +263,16 @@ export MINIKUBE_HOME="${TEST_HOME}/.minikube"
export MINIKUBE_WANTREPORTERRORPROMPT=False export MINIKUBE_WANTREPORTERRORPROMPT=False
export KUBECONFIG="${TEST_HOME}/kubeconfig" 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.
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
fi
# Display the default image URL # Display the default image URL
echo "" echo ""
echo ">> ISO URL" echo ">> ISO URL"
@ -274,9 +306,6 @@ ${SUDO_PREFIX} rm -f "${KUBECONFIG}" || true
rmdir "${TEST_HOME}" rmdir "${TEST_HOME}"
echo ">> ${TEST_HOME} completed at $(date)" echo ">> ${TEST_HOME} completed at $(date)"
# Build the gvisor image. This will be copied into minikube and loaded by ctr.
docker build -t gcr.io/k8s-minikube/gvisor-addon:latest -f testdata/gvisor-addon-Dockerfile out
if [[ "${MINIKUBE_LOCATION}" != "master" ]]; then if [[ "${MINIKUBE_LOCATION}" != "master" ]]; then
readonly target_url="https://storage.googleapis.com/minikube-builds/logs/${MINIKUBE_LOCATION}/${JOB_NAME}.txt" readonly target_url="https://storage.googleapis.com/minikube-builds/logs/${MINIKUBE_LOCATION}/${JOB_NAME}.txt"
curl -s "https://api.github.com/repos/kubernetes/minikube/statuses/${COMMIT}?access_token=$access_token" \ curl -s "https://api.github.com/repos/kubernetes/minikube/statuses/${COMMIT}?access_token=$access_token" \

View File

@ -0,0 +1,64 @@
#!/bin/bash
# Copyright 2016 The Kubernetes Authors All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -eux -o pipefail
if (($# < 2)); then
echo "ERROR: given ! ($#) number of parameters but expect 2."
echo "USAGE: ./check_and_install_golang.sh VERSION_TO_INSTALL INSTALL_PATH"
exit 1
fi
VERSION_TO_INSTALL=${1}
INSTALL_PATH=${2}
# installs or updates golang if right version doesn't exists
function check_and_install_golang() {
if ! go version &>/dev/null; then
echo "WARNING: No golang installation found in your enviroment."
install_golang "$VERSION_TO_INSTALL" "$INSTALL_PATH"
return
fi
# golang has been installed and check its version
if [[ $(go version) =~ (([0-9]+)\.([0-9]+).([0-9]+).([\.0-9]*)) ]]; then
HOST_VERSION=${BASH_REMATCH[1]}
if [ $HOST_VERSION = $VERSION_TO_INSTALL ]; then
echo "go version on the host looks good : $HOST_VERSION"
else
echo "WARNING: expected go version to be $VERSION_TO_INSTALL but got $HOST_VERSION"
install_golang "$VERSION_TO_INSTALL" "$INSTALL_PATH"
fi
else
echo "ERROR: Failed to parse golang version: $HOST_VERSION"
return
fi
}
# install_golang takes two parameters version and path to install.
function install_golang() {
echo "Installing golang version: $1 on $2"
pushd /tmp >/dev/null
# using sudo because previously installed versions might have been installed by a different user.
# as it was the case on jenkins VM.
sudo curl -qL -O "https://storage.googleapis.com/golang/go${1}.linux-amd64.tar.gz" &&
sudo tar xfa go${1}.linux-amd64.tar.gz &&
sudo rm -rf "${2}/go" &&
sudo mv go "${2}/" && sudo chown -R $(whoami): ${2}/go
popd >/dev/null
}
check_and_install_golang

View File

@ -25,6 +25,11 @@ set -eux -o pipefail
readonly bucket="minikube-builds" readonly bucket="minikube-builds"
# Make sure the right golang version is installed based on Makefile
WANT_GOLANG_VERSION=$(grep '^GO_VERSION' Makefile | awk '{ print $3 }')
./hack/jenkins/installers/check_install_golang.sh $WANT_GOLANG_VERSION /usr/local
declare -rx BUILD_IN_DOCKER=y declare -rx BUILD_IN_DOCKER=y
declare -rx GOPATH=/var/lib/jenkins/go declare -rx GOPATH=/var/lib/jenkins/go
declare -rx ISO_BUCKET="${bucket}/${ghprbPullId}" declare -rx ISO_BUCKET="${bucket}/${ghprbPullId}"

View File

@ -31,6 +31,11 @@ export DEB_VERSION=${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}
export RPM_VERSION=${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD} export RPM_VERSION=${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}
export GOPATH=~/go export GOPATH=~/go
# Make sure the right golang version is installed based on Makefile
WANT_GOLANG_VERSION=$(grep '^GO_VERSION' Makefile | awk '{ print $3 }')
./hack/jenkins/installers/check_install_golang.sh $WANT_GOLANG_VERSION /usr/local
# Make sure the tag matches the Makefile # Make sure the tag matches the Makefile
cat Makefile | grep "VERSION_MAJOR ?=" | grep $VERSION_MAJOR cat Makefile | grep "VERSION_MAJOR ?=" | grep $VERSION_MAJOR
cat Makefile | grep "VERSION_MINOR ?=" | grep $VERSION_MINOR cat Makefile | grep "VERSION_MINOR ?=" | grep $VERSION_MINOR

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package util package kapi
import ( import (
"context" "context"
@ -29,15 +29,13 @@ import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
watchtools "k8s.io/client-go/tools/watch" watchtools "k8s.io/client-go/tools/watch"
"k8s.io/kubernetes/cmd/kubeadm/app/constants" kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/minikube/pkg/minikube/proxy" "k8s.io/minikube/pkg/minikube/proxy"
) )
@ -48,30 +46,8 @@ var (
ReasonableStartTime = time.Minute * 5 ReasonableStartTime = time.Minute * 5
) )
// PodStore stores pods // Client gets the kubernetes client from default kubeconfig
type PodStore struct { func Client(kubectlContext ...string) (kubernetes.Interface, error) {
cache.Store
stopCh chan struct{}
Reflector *cache.Reflector
}
// List lists the pods
func (s *PodStore) List() []*core.Pod {
objects := s.Store.List()
pods := make([]*core.Pod, 0)
for _, o := range objects {
pods = append(pods, o.(*core.Pod))
}
return pods
}
// Stop stops the pods
func (s *PodStore) Stop() {
close(s.stopCh)
}
// GetClient gets the client from config
func GetClient(kubectlContext ...string) (kubernetes.Interface, error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
configOverrides := &clientcmd.ConfigOverrides{} configOverrides := &clientcmd.ConfigOverrides{}
if kubectlContext != nil { if kubectlContext != nil {
@ -92,50 +68,16 @@ func GetClient(kubectlContext ...string) (kubernetes.Interface, error) {
return client, nil return client, nil
} }
// NewPodStore creates a new PodStore
func NewPodStore(c kubernetes.Interface, namespace string, label fmt.Stringer, field fmt.Stringer) *PodStore {
lw := &cache.ListWatch{
ListFunc: func(options meta.ListOptions) (runtime.Object, error) {
options.LabelSelector = label.String()
options.FieldSelector = field.String()
obj, err := c.CoreV1().Pods(namespace).List(options)
return runtime.Object(obj), err
},
WatchFunc: func(options meta.ListOptions) (watch.Interface, error) {
options.LabelSelector = label.String()
options.FieldSelector = field.String()
return c.CoreV1().Pods(namespace).Watch(options)
},
}
store := cache.NewStore(cache.MetaNamespaceKeyFunc)
stopCh := make(chan struct{})
reflector := cache.NewReflector(lw, &core.Pod{}, store, 0)
go reflector.Run(stopCh)
return &PodStore{Store: store, stopCh: stopCh, Reflector: reflector}
}
// StartPods starts all pods
func StartPods(c kubernetes.Interface, namespace string, pod core.Pod, waitForRunning bool) error {
pod.ObjectMeta.Labels["name"] = pod.Name
if waitForRunning {
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": pod.Name}))
err := WaitForPodsWithLabelRunning(c, namespace, label)
if err != nil {
return fmt.Errorf("error waiting for pod %s to be running: %v", pod.Name, err)
}
}
return nil
}
// WaitForPodsWithLabelRunning waits for all matching pods to become Running and at least one matching pod exists. // WaitForPodsWithLabelRunning waits for all matching pods to become Running and at least one matching pod exists.
func WaitForPodsWithLabelRunning(c kubernetes.Interface, ns string, label labels.Selector) error { func WaitForPodsWithLabelRunning(c kubernetes.Interface, ns string, label labels.Selector, timeOut ...time.Duration) error {
start := time.Now()
glog.Infof("Waiting for pod with label %q in ns %q ...", ns, label) glog.Infof("Waiting for pod with label %q in ns %q ...", ns, label)
lastKnownPodNumber := -1 lastKnownPodNumber := -1
return wait.PollImmediate(constants.APICallRetryInterval, ReasonableStartTime, func() (bool, error) { f := func() (bool, error) {
listOpts := meta.ListOptions{LabelSelector: label.String()} listOpts := meta.ListOptions{LabelSelector: label.String()}
pods, err := c.CoreV1().Pods(ns).List(listOpts) pods, err := c.CoreV1().Pods(ns).List(listOpts)
if err != nil { if err != nil {
glog.Infof("error getting Pods with label selector %q [%v]\n", label.String(), err) glog.Infof("temporary error: getting Pods with label selector %q : [%v]\n", label.String(), err)
return false, nil return false, nil
} }
@ -150,45 +92,23 @@ func WaitForPodsWithLabelRunning(c kubernetes.Interface, ns string, label labels
for _, pod := range pods.Items { for _, pod := range pods.Items {
if pod.Status.Phase != core.PodRunning { if pod.Status.Phase != core.PodRunning {
glog.Infof("waiting for pod %q, current state: %s: [%v]\n", label.String(), pod.Status.Phase, err)
return false, nil return false, nil
} }
} }
return true, nil return true, nil
}) }
t := ReasonableStartTime
if timeOut != nil {
t = timeOut[0]
}
err := wait.PollImmediate(kconst.APICallRetryInterval, t, f)
glog.Infof("duration metric: took %s to wait for %s ...", time.Since(start), label)
return err
} }
// WaitForPodDelete waits for a pod to be deleted // WaitForRCToStabilize waits till the RC has a matching generation/replica count between spec and status. used by integration tests
func WaitForPodDelete(c kubernetes.Interface, ns string, label fmt.Stringer) error {
return wait.PollImmediate(constants.APICallRetryInterval, ReasonableMutateTime, func() (bool, error) {
listOpts := meta.ListOptions{LabelSelector: label.String()}
pods, err := c.CoreV1().Pods(ns).List(listOpts)
if err != nil {
glog.Infof("error getting Pods with label selector %q [%v]\n", label.String(), err)
return false, nil
}
return len(pods.Items) == 0, nil
})
}
// WaitForEvent waits for the given event to appear
func WaitForEvent(c kubernetes.Interface, ns string, reason string) error {
return wait.PollImmediate(constants.APICallRetryInterval, ReasonableMutateTime, func() (bool, error) {
events, err := c.EventsV1beta1().Events("default").List(meta.ListOptions{})
if err != nil {
glog.Infof("error getting events: %v", err)
return false, nil
}
for _, e := range events.Items {
if e.Reason == reason {
return true, nil
}
}
return false, nil
})
}
// WaitForRCToStabilize waits till the RC has a matching generation/replica count between spec and status.
func WaitForRCToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error { func WaitForRCToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error {
options := meta.ListOptions{FieldSelector: fields.Set{ options := meta.ListOptions{FieldSelector: fields.Set{
"metadata.name": name, "metadata.name": name,
@ -222,7 +142,7 @@ func WaitForRCToStabilize(c kubernetes.Interface, ns, name string, timeout time.
return err return err
} }
// WaitForDeploymentToStabilize waits till the Deployment has a matching generation/replica count between spec and status. // WaitForDeploymentToStabilize waits till the Deployment has a matching generation/replica count between spec and status. used by integrationt tests
func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error { func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error {
options := meta.ListOptions{FieldSelector: fields.Set{ options := meta.ListOptions{FieldSelector: fields.Set{
"metadata.name": name, "metadata.name": name,
@ -281,32 +201,6 @@ func WaitForService(c kubernetes.Interface, namespace, name string, exist bool,
return nil return nil
} }
// WaitForServiceEndpointsNum waits until the amount of endpoints that implement service to expectNum.
func WaitForServiceEndpointsNum(c kubernetes.Interface, namespace, serviceName string, expectNum int, interval, timeout time.Duration) error {
return wait.Poll(interval, timeout, func() (bool, error) {
glog.Infof("Waiting for amount of service:%s endpoints to be %d", serviceName, expectNum)
list, err := c.CoreV1().Endpoints(namespace).List(meta.ListOptions{})
if err != nil {
return false, err
}
for _, e := range list.Items {
if e.Name == serviceName && countEndpointsNum(&e) == expectNum {
return true, nil
}
}
return false, nil
})
}
func countEndpointsNum(e *core.Endpoints) int {
num := 0
for _, sub := range e.Subsets {
num += len(sub.Addresses)
}
return num
}
// IsRetryableAPIError returns if this error is retryable or not // IsRetryableAPIError returns if this error is retryable or not
func IsRetryableAPIError(err error) bool { func IsRetryableAPIError(err error) bool {
return apierr.IsTimeout(err) || apierr.IsServerTimeout(err) || apierr.IsTooManyRequests(err) || apierr.IsInternalError(err) return apierr.IsTimeout(err) || apierr.IsServerTimeout(err) || apierr.IsTooManyRequests(err) || apierr.IsInternalError(err)

View File

@ -18,6 +18,7 @@ package bootstrapper
import ( import (
"net" "net"
"time"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
@ -39,7 +40,7 @@ type Bootstrapper interface {
UpdateCluster(config.KubernetesConfig) error UpdateCluster(config.KubernetesConfig) error
RestartCluster(config.KubernetesConfig) error RestartCluster(config.KubernetesConfig) error
DeleteCluster(config.KubernetesConfig) error DeleteCluster(config.KubernetesConfig) error
WaitCluster(config.KubernetesConfig) error WaitCluster(config.KubernetesConfig, time.Duration) error
// LogCommands returns a map of log type to a command which will display that log. // LogCommands returns a map of log type to a command which will display that log.
LogCommands(LogOptions) map[string]string LogCommands(LogOptions) map[string]string
SetupCerts(cfg config.KubernetesConfig) error SetupCerts(cfg config.KubernetesConfig) error

View File

@ -35,6 +35,8 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/command"
@ -182,13 +184,13 @@ func (k *Bootstrapper) LogCommands(o bootstrapper.LogOptions) map[string]string
} }
// createFlagsFromExtraArgs converts kubeadm extra args into flags to be supplied from the commad linne // createFlagsFromExtraArgs converts kubeadm extra args into flags to be supplied from the commad linne
func createFlagsFromExtraArgs(extraOptions util.ExtraOptionSlice) string { func createFlagsFromExtraArgs(extraOptions config.ExtraOptionSlice) string {
kubeadmExtraOpts := extraOptions.AsMap().Get(Kubeadm) kubeadmExtraOpts := extraOptions.AsMap().Get(Kubeadm)
// kubeadm allows only a small set of parameters to be supplied from the command line when the --config param // kubeadm allows only a small set of parameters to be supplied from the command line when the --config param
// is specified, here we remove those that are not allowed // is specified, here we remove those that are not allowed
for opt := range kubeadmExtraOpts { for opt := range kubeadmExtraOpts {
if !util.ContainsString(KubeadmExtraArgsWhitelist[KubeadmCmdParam], opt) { if !config.ContainsParam(KubeadmExtraArgsWhitelist[KubeadmCmdParam], opt) {
// kubeadmExtraOpts is a copy so safe to delete // kubeadmExtraOpts is a copy so safe to delete
delete(kubeadmExtraOpts, opt) delete(kubeadmExtraOpts, opt)
} }
@ -198,7 +200,7 @@ func createFlagsFromExtraArgs(extraOptions util.ExtraOptionSlice) string {
// StartCluster starts the cluster // StartCluster starts the cluster
func (k *Bootstrapper) StartCluster(k8s config.KubernetesConfig) error { func (k *Bootstrapper) StartCluster(k8s config.KubernetesConfig) error {
version, err := ParseKubernetesVersion(k8s.KubernetesVersion) version, err := parseKubernetesVersion(k8s.KubernetesVersion)
if err != nil { if err != nil {
return errors.Wrap(err, "parsing kubernetes version") return errors.Wrap(err, "parsing kubernetes version")
} }
@ -307,13 +309,13 @@ func addAddons(files *[]assets.CopyableFile, data interface{}) error {
} }
// WaitCluster blocks until Kubernetes appears to be healthy. // WaitCluster blocks until Kubernetes appears to be healthy.
func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig) error { func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig, timeout time.Duration) error {
// Do not wait for "k8s-app" pods in the case of CNI, as they are managed // Do not wait for "k8s-app" pods in the case of CNI, as they are managed
// by a CNI plugin which is usually started after minikube has been brought // by a CNI plugin which is usually started after minikube has been brought
// up. Otherwise, minikube won't start, as "k8s-app" pods are not ready. // up. Otherwise, minikube won't start, as "k8s-app" pods are not ready.
componentsOnly := k8s.NetworkPlugin == "cni" componentsOnly := k8s.NetworkPlugin == "cni"
out.T(out.WaitingPods, "Waiting for:") out.T(out.WaitingPods, "Waiting for:")
client, err := util.GetClient() client, err := kapi.Client()
if err != nil { if err != nil {
return errors.Wrap(err, "k8s client") return errors.Wrap(err, "k8s client")
} }
@ -326,13 +328,12 @@ func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig) error {
} }
for _, p := range PodsByLayer { for _, p := range PodsByLayer {
if componentsOnly && p.key != "component" { if componentsOnly && p.key != "component" { // skip component check if network plugin is cni
continue continue
} }
out.String(" %s", p.name) out.String(" %s", p.name)
selector := labels.SelectorFromSet(labels.Set(map[string]string{p.key: p.value})) selector := labels.SelectorFromSet(labels.Set(map[string]string{p.key: p.value}))
if err := util.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "kube-system", selector, timeout); err != nil {
return errors.Wrap(err, fmt.Sprintf("waiting for %s=%s", p.key, p.value)) return errors.Wrap(err, fmt.Sprintf("waiting for %s=%s", p.key, p.value))
} }
} }
@ -342,7 +343,7 @@ func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig) error {
// RestartCluster restarts the Kubernetes cluster configured by kubeadm // RestartCluster restarts the Kubernetes cluster configured by kubeadm
func (k *Bootstrapper) RestartCluster(k8s config.KubernetesConfig) error { func (k *Bootstrapper) RestartCluster(k8s config.KubernetesConfig) error {
version, err := ParseKubernetesVersion(k8s.KubernetesVersion) version, err := parseKubernetesVersion(k8s.KubernetesVersion)
if err != nil { if err != nil {
return errors.Wrap(err, "parsing kubernetes version") return errors.Wrap(err, "parsing kubernetes version")
} }
@ -398,8 +399,9 @@ func (k *Bootstrapper) waitForAPIServer(k8s config.KubernetesConfig) error {
return fmt.Errorf("apiserver process never appeared") return fmt.Errorf("apiserver process never appeared")
} }
glog.Infof("Waiting for apiserver status ...") start := time.Now()
return wait.PollImmediate(time.Millisecond*300, time.Minute*1, func() (bool, error) { glog.Infof("Waiting for apiserver ...")
f := func() (bool, error) {
status, err := k.GetAPIServerStatus(net.ParseIP(k8s.NodeIP), k8s.NodePort) status, err := k.GetAPIServerStatus(net.ParseIP(k8s.NodeIP), k8s.NodePort)
glog.Infof("apiserver status: %s, err: %v", status, err) glog.Infof("apiserver status: %s, err: %v", status, err)
if err != nil { if err != nil {
@ -409,7 +411,10 @@ func (k *Bootstrapper) waitForAPIServer(k8s config.KubernetesConfig) error {
return false, nil return false, nil
} }
return true, nil return true, nil
}) }
err = wait.PollImmediate(kconst.APICallRetryInterval, kconst.DefaultControlPlaneTimeout, f)
glog.Infof("duration metric: took %s to wait for apiserver status ...", time.Since(start))
return err
} }
// DeleteCluster removes the components that were started earlier // DeleteCluster removes the components that were started earlier
@ -425,7 +430,7 @@ func (k *Bootstrapper) DeleteCluster(k8s config.KubernetesConfig) error {
// PullImages downloads images that will be used by RestartCluster // PullImages downloads images that will be used by RestartCluster
func (k *Bootstrapper) PullImages(k8s config.KubernetesConfig) error { func (k *Bootstrapper) PullImages(k8s config.KubernetesConfig) error {
version, err := ParseKubernetesVersion(k8s.KubernetesVersion) version, err := parseKubernetesVersion(k8s.KubernetesVersion)
if err != nil { if err != nil {
return errors.Wrap(err, "parsing kubernetes version") return errors.Wrap(err, "parsing kubernetes version")
} }
@ -448,7 +453,7 @@ func (k *Bootstrapper) SetupCerts(k8s config.KubernetesConfig) error {
// NewKubeletConfig generates a new systemd unit containing a configured kubelet // NewKubeletConfig generates a new systemd unit containing a configured kubelet
// based on the options present in the KubernetesConfig. // based on the options present in the KubernetesConfig.
func NewKubeletConfig(k8s config.KubernetesConfig, r cruntime.Manager) ([]byte, error) { func NewKubeletConfig(k8s config.KubernetesConfig, r cruntime.Manager) ([]byte, error) {
version, err := ParseKubernetesVersion(k8s.KubernetesVersion) version, err := parseKubernetesVersion(k8s.KubernetesVersion)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "parsing kubernetes version") return nil, errors.Wrap(err, "parsing kubernetes version")
} }
@ -551,7 +556,7 @@ func (k *Bootstrapper) UpdateCluster(cfg config.KubernetesConfig) error {
} }
// createExtraComponentConfig generates a map of component to extra args for all of the components except kubeadm // createExtraComponentConfig generates a map of component to extra args for all of the components except kubeadm
func createExtraComponentConfig(extraOptions util.ExtraOptionSlice, version semver.Version, componentFeatureArgs string) ([]ComponentExtraArgs, error) { func createExtraComponentConfig(extraOptions config.ExtraOptionSlice, version semver.Version, componentFeatureArgs string) ([]ComponentExtraArgs, error) {
extraArgsSlice, err := NewComponentExtraArgs(extraOptions, version, componentFeatureArgs) extraArgsSlice, err := NewComponentExtraArgs(extraOptions, version, componentFeatureArgs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -571,7 +576,7 @@ func createExtraComponentConfig(extraOptions util.ExtraOptionSlice, version semv
// generateConfig generates the kubeadm.yaml file // generateConfig generates the kubeadm.yaml file
func generateConfig(k8s config.KubernetesConfig, r cruntime.Manager) ([]byte, error) { func generateConfig(k8s config.KubernetesConfig, r cruntime.Manager) ([]byte, error) {
version, err := ParseKubernetesVersion(k8s.KubernetesVersion) version, err := parseKubernetesVersion(k8s.KubernetesVersion)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "parsing kubernetes version") return nil, errors.Wrap(err, "parsing kubernetes version")
} }

View File

@ -26,7 +26,6 @@ import (
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/cruntime"
"k8s.io/minikube/pkg/util"
) )
func TestGenerateKubeletConfig(t *testing.T) { func TestGenerateKubeletConfig(t *testing.T) {
@ -145,29 +144,29 @@ ExecStart=/var/lib/minikube/binaries/v1.15.2/kubelet --authorization-mode=Webhoo
} }
} }
func getExtraOpts() []util.ExtraOption { func getExtraOpts() []config.ExtraOption {
return util.ExtraOptionSlice{ return config.ExtraOptionSlice{
util.ExtraOption{ config.ExtraOption{
Component: Apiserver, Component: Apiserver,
Key: "fail-no-swap", Key: "fail-no-swap",
Value: "true", Value: "true",
}, },
util.ExtraOption{ config.ExtraOption{
Component: ControllerManager, Component: ControllerManager,
Key: "kube-api-burst", Key: "kube-api-burst",
Value: "32", Value: "32",
}, },
util.ExtraOption{ config.ExtraOption{
Component: Scheduler, Component: Scheduler,
Key: "scheduler-name", Key: "scheduler-name",
Value: "mini-scheduler", Value: "mini-scheduler",
}, },
util.ExtraOption{ config.ExtraOption{
Component: Kubeadm, Component: Kubeadm,
Key: "ignore-preflight-errors", Key: "ignore-preflight-errors",
Value: "true", Value: "true",
}, },
util.ExtraOption{ config.ExtraOption{
Component: Kubeadm, Component: Kubeadm,
Key: "dry-run", Key: "dry-run",
Value: "true", Value: "true",
@ -175,9 +174,9 @@ func getExtraOpts() []util.ExtraOption {
} }
} }
func getExtraOptsPodCidr() []util.ExtraOption { func getExtraOptsPodCidr() []config.ExtraOption {
return util.ExtraOptionSlice{ return config.ExtraOptionSlice{
util.ExtraOption{ config.ExtraOption{
Component: Kubeadm, Component: Kubeadm,
Key: "pod-network-cidr", Key: "pod-network-cidr",
Value: "192.168.32.0/20", Value: "192.168.32.0/20",
@ -229,7 +228,7 @@ func TestGenerateConfig(t *testing.T) {
{"crio", "crio", false, config.KubernetesConfig{}}, {"crio", "crio", false, config.KubernetesConfig{}},
{"options", "docker", false, config.KubernetesConfig{ExtraOptions: extraOpts}}, {"options", "docker", false, config.KubernetesConfig{ExtraOptions: extraOpts}},
{"crio-options-gates", "crio", false, config.KubernetesConfig{ExtraOptions: extraOpts, FeatureGates: "a=b"}}, {"crio-options-gates", "crio", false, config.KubernetesConfig{ExtraOptions: extraOpts, FeatureGates: "a=b"}},
{"unknown-component", "docker", true, config.KubernetesConfig{ExtraOptions: util.ExtraOptionSlice{util.ExtraOption{Component: "not-a-real-component", Key: "killswitch", Value: "true"}}}}, {"unknown-component", "docker", true, config.KubernetesConfig{ExtraOptions: config.ExtraOptionSlice{config.ExtraOption{Component: "not-a-real-component", Key: "killswitch", Value: "true"}}}},
{"containerd-api-port", "containerd", false, config.KubernetesConfig{NodePort: 12345}}, {"containerd-api-port", "containerd", false, config.KubernetesConfig{NodePort: 12345}},
{"containerd-pod-network-cidr", "containerd", false, config.KubernetesConfig{ExtraOptions: extraOptsPodCidr}}, {"containerd-pod-network-cidr", "containerd", false, config.KubernetesConfig{ExtraOptions: extraOptsPodCidr}},
{"image-repository", "docker", false, config.KubernetesConfig{ImageRepository: "test/repo"}}, {"image-repository", "docker", false, config.KubernetesConfig{ImageRepository: "test/repo"}},

View File

@ -27,6 +27,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/kubernetes/cmd/kubeadm/app/features" "k8s.io/kubernetes/cmd/kubeadm/app/features"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/util"
) )
@ -43,7 +44,7 @@ const (
// ExtraConfigForComponent generates a map of flagname-value pairs for a k8s // ExtraConfigForComponent generates a map of flagname-value pairs for a k8s
// component. // component.
func ExtraConfigForComponent(component string, opts util.ExtraOptionSlice, version semver.Version) (map[string]string, error) { func ExtraConfigForComponent(component string, opts config.ExtraOptionSlice, version semver.Version) (map[string]string, error) {
versionedOpts, err := DefaultOptionsForComponentAndVersion(component, version) versionedOpts, err := DefaultOptionsForComponentAndVersion(component, version)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "setting version specific options for %s", component) return nil, errors.Wrapf(err, "setting version specific options for %s", component)
@ -78,7 +79,7 @@ var componentToKubeadmConfigKey = map[string]string{
} }
// NewComponentExtraArgs creates a new ComponentExtraArgs // NewComponentExtraArgs creates a new ComponentExtraArgs
func NewComponentExtraArgs(opts util.ExtraOptionSlice, version semver.Version, featureGates string) ([]ComponentExtraArgs, error) { func NewComponentExtraArgs(opts config.ExtraOptionSlice, version semver.Version, featureGates string) ([]ComponentExtraArgs, error) {
var kubeadmExtraArgs []ComponentExtraArgs var kubeadmExtraArgs []ComponentExtraArgs
for _, extraOpt := range opts { for _, extraOpt := range opts {
if _, ok := componentToKubeadmConfigKey[extraOpt.Component]; !ok { if _, ok := componentToKubeadmConfigKey[extraOpt.Component]; !ok {
@ -158,8 +159,8 @@ func Supports(featureName string) bool {
return false return false
} }
// ParseKubernetesVersion parses the kubernetes version // parseKubernetesVersion parses the kubernetes version
func ParseKubernetesVersion(version string) (semver.Version, error) { func parseKubernetesVersion(version string) (semver.Version, error) {
// Strip leading 'v' prefix from version for semver parsing // Strip leading 'v' prefix from version for semver parsing
v, err := semver.Make(version[1:]) v, err := semver.Make(version[1:])
if err != nil { if err != nil {
@ -182,45 +183,9 @@ func convertToFlags(opts map[string]string) string {
return strings.Join(flags, " ") return strings.Join(flags, " ")
} }
// VersionedExtraOption holds information on flags to apply to a specific range var versionSpecificOpts = []config.VersionedExtraOption{
// of versions
type VersionedExtraOption struct {
// Special Cases:
//
// If LessThanOrEqual and GreaterThanOrEqual are both nil, the flag will be applied
// to all versions
//
// If LessThanOrEqual == GreaterThanOrEqual, the flag will only be applied to that
// specific version
// The flag and component that will be set
Option util.ExtraOption
// This flag will only be applied to versions before or equal to this version
// If it is the default value, it will have no upper bound on versions the
// flag is applied to
LessThanOrEqual semver.Version
// The flag will only be applied to versions after or equal to this version
// If it is the default value, it will have no lower bound on versions the
// flag is applied to
GreaterThanOrEqual semver.Version
}
// NewUnversionedOption returns a VersionedExtraOption that applies to all versions.
func NewUnversionedOption(component, k, v string) VersionedExtraOption {
return VersionedExtraOption{
Option: util.ExtraOption{
Component: component,
Key: k,
Value: v,
},
}
}
var versionSpecificOpts = []VersionedExtraOption{
{ {
Option: util.ExtraOption{ Option: config.ExtraOption{
Component: Kubelet, Component: Kubelet,
Key: "fail-swap-on", Key: "fail-swap-on",
Value: "false", Value: "false",
@ -228,22 +193,22 @@ var versionSpecificOpts = []VersionedExtraOption{
GreaterThanOrEqual: semver.MustParse("1.8.0-alpha.0"), GreaterThanOrEqual: semver.MustParse("1.8.0-alpha.0"),
}, },
// Kubeconfig args // Kubeconfig args
NewUnversionedOption(Kubelet, "kubeconfig", "/etc/kubernetes/kubelet.conf"), config.NewUnversionedOption(Kubelet, "kubeconfig", "/etc/kubernetes/kubelet.conf"),
NewUnversionedOption(Kubelet, "bootstrap-kubeconfig", "/etc/kubernetes/bootstrap-kubelet.conf"), config.NewUnversionedOption(Kubelet, "bootstrap-kubeconfig", "/etc/kubernetes/bootstrap-kubelet.conf"),
{ {
Option: util.ExtraOption{ Option: config.ExtraOption{
Component: Kubelet, Component: Kubelet,
Key: "require-kubeconfig", Key: "require-kubeconfig",
Value: "true", Value: "true",
}, },
LessThanOrEqual: semver.MustParse("1.9.10"), LessThanOrEqual: semver.MustParse("1.9.10"),
}, },
NewUnversionedOption(Kubelet, "hostname-override", constants.DefaultNodeName), config.NewUnversionedOption(Kubelet, "hostname-override", constants.DefaultNodeName),
// System pods args // System pods args
NewUnversionedOption(Kubelet, "pod-manifest-path", constants.GuestManifestsDir), config.NewUnversionedOption(Kubelet, "pod-manifest-path", constants.GuestManifestsDir),
{ {
Option: util.ExtraOption{ Option: config.ExtraOption{
Component: Kubelet, Component: Kubelet,
Key: "allow-privileged", Key: "allow-privileged",
Value: "true", Value: "true",
@ -252,17 +217,17 @@ var versionSpecificOpts = []VersionedExtraOption{
}, },
// Network args // Network args
NewUnversionedOption(Kubelet, "cluster-dns", "10.96.0.10"), config.NewUnversionedOption(Kubelet, "cluster-dns", "10.96.0.10"),
NewUnversionedOption(Kubelet, "cluster-domain", "cluster.local"), config.NewUnversionedOption(Kubelet, "cluster-domain", "cluster.local"),
// Auth args // Auth args
NewUnversionedOption(Kubelet, "authorization-mode", "Webhook"), config.NewUnversionedOption(Kubelet, "authorization-mode", "Webhook"),
NewUnversionedOption(Kubelet, "client-ca-file", path.Join(constants.GuestCertsDir, "ca.crt")), config.NewUnversionedOption(Kubelet, "client-ca-file", path.Join(constants.GuestCertsDir, "ca.crt")),
// Cgroup args // Cgroup args
NewUnversionedOption(Kubelet, "cgroup-driver", "cgroupfs"), config.NewUnversionedOption(Kubelet, "cgroup-driver", "cgroupfs"),
{ {
Option: util.ExtraOption{ Option: config.ExtraOption{
Component: Apiserver, Component: Apiserver,
Key: "admission-control", Key: "admission-control",
Value: strings.Join(util.DefaultLegacyAdmissionControllers, ","), Value: strings.Join(util.DefaultLegacyAdmissionControllers, ","),
@ -271,7 +236,7 @@ var versionSpecificOpts = []VersionedExtraOption{
GreaterThanOrEqual: semver.MustParse("1.9.0-alpha.0"), GreaterThanOrEqual: semver.MustParse("1.9.0-alpha.0"),
}, },
{ {
Option: util.ExtraOption{ Option: config.ExtraOption{
Component: Apiserver, Component: Apiserver,
Key: "enable-admission-plugins", Key: "enable-admission-plugins",
Value: strings.Join(util.DefaultLegacyAdmissionControllers, ","), Value: strings.Join(util.DefaultLegacyAdmissionControllers, ","),
@ -280,7 +245,7 @@ var versionSpecificOpts = []VersionedExtraOption{
LessThanOrEqual: semver.MustParse("1.13.1000"), LessThanOrEqual: semver.MustParse("1.13.1000"),
}, },
{ {
Option: util.ExtraOption{ Option: config.ExtraOption{
Component: Apiserver, Component: Apiserver,
Key: "enable-admission-plugins", Key: "enable-admission-plugins",
Value: strings.Join(util.DefaultV114AdmissionControllers, ","), Value: strings.Join(util.DefaultV114AdmissionControllers, ","),
@ -289,7 +254,7 @@ var versionSpecificOpts = []VersionedExtraOption{
}, },
{ {
Option: util.ExtraOption{ Option: config.ExtraOption{
Component: Kubelet, Component: Kubelet,
Key: "cadvisor-port", Key: "cadvisor-port",
Value: "0", Value: "0",

View File

@ -94,7 +94,7 @@ func TestVersionIsBetween(t *testing.T) {
} }
func TestParseKubernetesVersion(t *testing.T) { func TestParseKubernetesVersion(t *testing.T) {
version, err := ParseKubernetesVersion("v1.8.0-alpha.5") version, err := parseKubernetesVersion("v1.8.0-alpha.5")
if err != nil { if err != nil {
t.Fatalf("Error parsing version: %v", err) t.Fatalf("Error parsing version: %v", err)
} }

View File

@ -160,7 +160,7 @@ func configureHost(h *host.Host, e *engine.Options) error {
if err != nil { if err != nil {
return errors.Wrap(err, "detecting provisioner") return errors.Wrap(err, "detecting provisioner")
} }
glog.Infof("Provisioning: %+v", *h.HostOptions) glog.Infof("Provisioning with %s: %+v", provisioner.String(), *h.HostOptions)
if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions); err != nil { if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions); err != nil {
return errors.Wrap(err, "provision") return errors.Wrap(err, "provision")
} }
@ -338,6 +338,7 @@ func engineOptions(config cfg.MachineConfig) *engine.Options {
InsecureRegistry: append([]string{pkgutil.DefaultServiceCIDR}, config.InsecureRegistry...), InsecureRegistry: append([]string{pkgutil.DefaultServiceCIDR}, config.InsecureRegistry...),
RegistryMirror: config.RegistryMirror, RegistryMirror: config.RegistryMirror,
ArbitraryFlags: config.DockerOpt, ArbitraryFlags: config.DockerOpt,
InstallURL: drivers.DefaultEngineInstallURL,
} }
return &o return &o
} }

View File

@ -59,7 +59,7 @@ type MinikubeConfig map[string]interface{}
// Get gets a named value from config // Get gets a named value from config
func Get(name string) (string, error) { func Get(name string) (string, error) {
m, err := ReadConfig() m, err := ReadConfig(constants.ConfigFile)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -88,11 +88,7 @@ func WriteConfig(configFile string, m MinikubeConfig) error {
} }
// ReadConfig reads in the JSON minikube config // ReadConfig reads in the JSON minikube config
func ReadConfig() (MinikubeConfig, error) { func ReadConfig(configFile string) (MinikubeConfig, error) {
return readConfig(constants.ConfigFile)
}
func readConfig(configFile string) (MinikubeConfig, error) {
f, err := os.Open(configFile) f, err := os.Open(configFile)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {

View File

@ -104,9 +104,9 @@ func Test_get(t *testing.T) {
} }
} }
func Test_readConfig(t *testing.T) { func TestReadConfig(t *testing.T) {
// non existing file // non existing file
mkConfig, err := readConfig("non_existing_file") mkConfig, err := ReadConfig("non_existing_file")
if err != nil { if err != nil {
t.Fatalf("Error not exepected but got %v", err) t.Fatalf("Error not exepected but got %v", err)
} }
@ -116,7 +116,7 @@ func Test_readConfig(t *testing.T) {
} }
// invalid config file // invalid config file
mkConfig, err = readConfig("./testdata/.minikube/config/invalid_config.json") mkConfig, err = ReadConfig("./testdata/.minikube/config/invalid_config.json")
if err == nil { if err == nil {
t.Fatalf("Error expected but got none") t.Fatalf("Error expected but got none")
} }
@ -126,7 +126,7 @@ func Test_readConfig(t *testing.T) {
} }
// valid config file // valid config file
mkConfig, err = readConfig("./testdata/.minikube/config/valid_config.json") mkConfig, err = ReadConfig("./testdata/.minikube/config/valid_config.json")
if err != nil { if err != nil {
t.Fatalf("Error not expected but got %v", err) t.Fatalf("Error not expected but got %v", err)
} }
@ -164,7 +164,7 @@ func TestWriteConfig(t *testing.T) {
} }
defer os.Remove(configFile.Name()) defer os.Remove(configFile.Name())
mkConfig, err := readConfig(configFile.Name()) mkConfig, err := ReadConfig(configFile.Name())
if err != nil { if err != nil {
t.Fatalf("Error not expected but got %v", err) t.Fatalf("Error not expected but got %v", err)
} }

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2016 The Kubernetes Authors All rights reserved. Copyright 2019 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package util package config
import ( import (
"fmt" "fmt"
@ -76,7 +76,7 @@ func (es *ExtraOptionSlice) String() string {
// component is not specified, all of the components are used. // component is not specified, all of the components are used.
func (es *ExtraOptionSlice) Get(key string, component ...string) string { func (es *ExtraOptionSlice) Get(key string, component ...string) string {
for _, opt := range *es { for _, opt := range *es {
if component == nil || ContainsString(component, opt.Component) { if component == nil || ContainsParam(component, opt.Component) {
if opt.Key == key { if opt.Key == key {
return opt.Value return opt.Value
} }
@ -107,3 +107,25 @@ func (es *ExtraOptionSlice) Type() string {
func (cm ComponentExtraOptionMap) Get(component string) map[string]string { func (cm ComponentExtraOptionMap) Get(component string) map[string]string {
return cm[component] return cm[component]
} }
// ContainsParam checks if a given slice of strings contains the provided string.
// If a modifier func is provided, it is called with the slice item before the comparation.
func ContainsParam(slice []string, s string) bool {
for _, item := range slice {
if item == s {
return true
}
}
return false
}
// NewUnversionedOption returns a VersionedExtraOption that applies to all versions.
func NewUnversionedOption(component, k, v string) VersionedExtraOption {
return VersionedExtraOption{
Option: ExtraOption{
Component: component,
Key: k,
Value: v,
},
}
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package util package config
import ( import (
"flag" "flag"

View File

@ -19,6 +19,7 @@ package config
import ( import (
"net" "net"
"github.com/blang/semver"
"k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/util"
) )
@ -82,8 +83,33 @@ type KubernetesConfig struct {
FeatureGates string FeatureGates string
ServiceCIDR string ServiceCIDR string
ImageRepository string ImageRepository string
ExtraOptions util.ExtraOptionSlice ExtraOptions ExtraOptionSlice
ShouldLoadCachedImages bool ShouldLoadCachedImages bool
EnableDefaultCNI bool EnableDefaultCNI bool
} }
// VersionedExtraOption holds information on flags to apply to a specific range
// of versions
type VersionedExtraOption struct {
// Special Cases:
//
// If LessThanOrEqual and GreaterThanOrEqual are both nil, the flag will be applied
// to all versions
//
// If LessThanOrEqual == GreaterThanOrEqual, the flag will only be applied to that
// specific version
// The flag and component that will be set
Option ExtraOption
// This flag will only be applied to versions before or equal to this version
// If it is the default value, it will have no upper bound on versions the
// flag is applied to
LessThanOrEqual semver.Version
// The flag will only be applied to versions after or equal to this version
// If it is the default value, it will have no lower bound on versions the
// flag is applied to
GreaterThanOrEqual semver.Version
}

View File

@ -92,7 +92,7 @@ func (r *Containerd) Enable(disOthers bool) error {
if err := enableIPForwarding(r.Runner); err != nil { if err := enableIPForwarding(r.Runner); err != nil {
return err return err
} }
// Oherwise, containerd will fail API requests with 'Unimplemented' // Otherwise, containerd will fail API requests with 'Unimplemented'
return r.Runner.Run("sudo systemctl restart containerd") return r.Runner.Run("sudo systemctl restart containerd")
} }

View File

@ -123,7 +123,7 @@ func (api *LocalClient) NewHost(driverName string, rawDriver []byte) (*host.Host
func (api *LocalClient) Load(name string) (*host.Host, error) { func (api *LocalClient) Load(name string) (*host.Host, error) {
h, err := api.Filestore.Load(name) h, err := api.Filestore.Load(name)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "filestore") return nil, errors.Wrapf(err, "filestore %q", name)
} }
var def registry.DriverDef var def registry.DriverDef

View File

@ -36,8 +36,6 @@ import (
"k8s.io/minikube/pkg/version" "k8s.io/minikube/pkg/version"
) )
const updateLinkPrefix = "https://github.com/kubernetes/minikube/releases/tag/v"
var ( var (
timeLayout = time.RFC1123 timeLayout = time.RFC1123
lastUpdateCheckFilePath = constants.MakeMiniPath("last_update_check") lastUpdateCheckFilePath = constants.MakeMiniPath("last_update_check")
@ -67,7 +65,7 @@ func MaybePrintUpdateText(url string, lastUpdatePath string) {
if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil { if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil {
glog.Errorf("write time failed: %v", err) glog.Errorf("write time failed: %v", err)
} }
url := fmt.Sprintf("%s/%s", updateLinkPrefix, latestVersion) url := "https://github.com/kubernetes/minikube/releases/tag/v" + latestVersion.String()
out.ErrT(out.WarningType, `minikube {{.version}} is available! Download it: {{.url}}`, out.V{"version": latestVersion, "url": url}) out.ErrT(out.WarningType, `minikube {{.version}} is available! Download it: {{.url}}`, out.V{"version": latestVersion, "url": url})
out.T(out.Tip, "To disable this notice, run: 'minikube config set WantUpdateNotification false'") out.T(out.Tip, "To disable this notice, run: 'minikube config set WantUpdateNotification false'")
} }

View File

@ -36,7 +36,7 @@ var (
Translations map[string]interface{} Translations map[string]interface{}
) )
// T translates the given string to the supplied language. // T translates the given string to the preferred language.
func T(s string) string { func T(s string) string {
if preferredLanguage == defaultLanguage { if preferredLanguage == defaultLanguage {
return s return s

View File

@ -69,6 +69,11 @@ func (p *BuildrootProvisioner) String() string {
return "buildroot" return "buildroot"
} }
// CompatibleWithHost checks if provisioner is compatible with host
func (p *BuildrootProvisioner) CompatibleWithHost() bool {
return p.OsReleaseInfo.ID == "buildroot"
}
// escapeSystemdDirectives escapes special characters in the input variables used to create the // escapeSystemdDirectives escapes special characters in the input variables used to create the
// systemd unit file, which would otherwise be interpreted as systemd directives. An example // systemd unit file, which would otherwise be interpreted as systemd directives. An example
// are template specifiers (e.g. '%i') which are predefined variables that get evaluated dynamically // are template specifiers (e.g. '%i') which are predefined variables that get evaluated dynamically

View File

@ -36,7 +36,7 @@ func WriteFile(filename string, data []byte, perm os.FileMode) (err error) {
lockErr := lock.TryLock() lockErr := lock.TryLock()
if lockErr != nil { if lockErr != nil {
glog.Warningf("temporary error : %v", lockErr.Error()) glog.Warningf("temporary error : %v", lockErr.Error())
return errors.Wrapf(lockErr, "falied to acquire lock for %s > ", filename) return errors.Wrapf(lockErr, "failed to acquire lock for %s > ", filename)
} }
return nil return nil
} }

View File

@ -200,14 +200,3 @@ func ConcatStrings(src []string, prefix string, postfix string) []string {
} }
return ret return ret
} }
// ContainsString checks if a given slice of strings contains the provided string.
// If a modifier func is provided, it is called with the slice item before the comparation.
func ContainsString(slice []string, s string) bool {
for _, item := range slice {
if item == s {
return true
}
}
return false
}

View File

@ -45,5 +45,5 @@ Then minikube is for you.
## Where should I go next? ## Where should I go next?
* [Getting Started](/start/): Get started with minikube * [Getting Started](/docs/start/): Get started with minikube
* [Examples](/examples/): Check out some minikube examples! * [Examples](/docs/examples/): Check out some minikube examples!

View File

@ -27,3 +27,16 @@ virt-host-validate
curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-kvm2 \ curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-kvm2 \
&& sudo install docker-machine-driver-kvm2 /usr/local/bin/ && sudo install docker-machine-driver-kvm2 /usr/local/bin/
``` ```
## Usage
To explicitly start minikube with KVM:
```shell
minikube start --vm-driver=kvm2
```
To make KVM the default driver:
```shell
minikube config set vm-driver kvm2
```

View File

@ -32,6 +32,21 @@ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-darwin
{{% /tab %}} {{% /tab %}}
{{% /tabs %}} {{% /tabs %}}
### Upgrading minikube
{{% tabs %}}
{{% tab "Brew" %}}
If the [Brew Package Manager](https://brew.sh/) is installed, use it to download and upgrade minikube:
```shell
rm /usr/local/bin/minikube
brew cask reinstall minikube
```
{{% /tab %}}
{{% /tabs %}}
## Hypervisor Setup ## Hypervisor Setup
{{% tabs %}} {{% tabs %}}

View File

@ -35,4 +35,4 @@ If you are looking for a solution tuned for iterative application development, c
- [Draft](https://draft.sh): see specific [minikube instructions](https://github.com/Azure/draft/blob/master/docs/install-minikube.md) - [Draft](https://draft.sh): see specific [minikube instructions](https://github.com/Azure/draft/blob/master/docs/install-minikube.md)
- [Okteto](https://github.com/okteto/okteto) - [Okteto](https://github.com/okteto/okteto)
- [Skaffold](http://github.com/ContainerTools/skaffold) - [Skaffold](https://github.com/GoogleContainerTools/skaffold)

View File

@ -0,0 +1,81 @@
// +build integration
/*
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 integration
import (
"strings"
"testing"
)
func TestConfig(t *testing.T) {
t.Parallel()
p := profileName(t)
mk := NewMinikubeRunner(t, p, "--wait=false")
tests := []struct {
cmd string
stdout string
stderr string
}{
{
cmd: "config unset cpus",
stdout: "",
stderr: "",
},
{
cmd: "config get cpus",
stdout: "",
stderr: "Error: specified key could not be found in config",
},
{
cmd: "config set cpus 2",
stdout: "! These changes will take effect upon a minikube delete and then a minikube start",
stderr: "",
},
{
cmd: "config get cpus",
stdout: "2",
stderr: "",
},
{
cmd: "config unset cpus",
stdout: "",
stderr: ""},
{
cmd: "config get cpus",
stdout: "",
stderr: "Error: specified key could not be found in config",
},
}
for _, tc := range tests {
stdout, stderr, _ := mk.RunCommandRetriable(tc.cmd)
if !compare(tc.stdout, stdout) {
t.Fatalf("Expected stdout to be: %s. Stdout was: %s Stderr: %s", tc.stdout, stdout, stderr)
}
if !compare(tc.stderr, stderr) {
t.Fatalf("Expected stderr to be: %s. Stdout was: %s Stderr: %s", tc.stderr, stdout, stderr)
}
}
}
func compare(s1, s2 string) bool {
return strings.TrimSpace(s1) == strings.TrimSpace(s2)
}

View File

@ -25,7 +25,7 @@ import (
"github.com/docker/machine/libmachine/state" "github.com/docker/machine/libmachine/state"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
commonutil "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/test/integration/util" "k8s.io/minikube/test/integration/util"
) )
@ -107,13 +107,13 @@ func deleteUntrustedWorkload(t *testing.T, profile string) {
// waitForGvisorControllerRunning waits for the gvisor controller pod to be running // waitForGvisorControllerRunning waits for the gvisor controller pod to be running
func waitForGvisorControllerRunning(p string) error { func waitForGvisorControllerRunning(p string) error {
client, err := commonutil.GetClient(p) client, err := kapi.Client(p)
if err != nil { if err != nil {
return errors.Wrap(err, "getting kubernetes client") return errors.Wrap(err, "getting kubernetes client")
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"kubernetes.io/minikube-addons": "gvisor"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"kubernetes.io/minikube-addons": "gvisor"}))
if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
return errors.Wrap(err, "waiting for gvisor controller pod to stabilize") return errors.Wrap(err, "waiting for gvisor controller pod to stabilize")
} }
return nil return nil
@ -121,13 +121,13 @@ func waitForGvisorControllerRunning(p string) error {
// waitForUntrustedNginxRunning waits for the untrusted nginx pod to start running // waitForUntrustedNginxRunning waits for the untrusted nginx pod to start running
func waitForUntrustedNginxRunning(miniProfile string) error { func waitForUntrustedNginxRunning(miniProfile string) error {
client, err := commonutil.GetClient(miniProfile) client, err := kapi.Client(miniProfile)
if err != nil { if err != nil {
return errors.Wrap(err, "getting kubernetes client") return errors.Wrap(err, "getting kubernetes client")
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"}))
if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "default", selector); err != nil {
return errors.Wrap(err, "waiting for nginx pods") return errors.Wrap(err, "waiting for nginx pods")
} }
return nil return nil

View File

@ -32,7 +32,7 @@ func TestMain(m *testing.M) {
os.Exit(m.Run()) os.Exit(m.Run())
} }
var startTimeout = flag.Int("timeout", 25, "number of minutes to wait for minikube start") var startTimeout = flag.Duration("timeout", 25*time.Minute, "max duration to wait for a full minikube start")
var binaryPath = flag.String("binary", "../../out/minikube", "path to minikube binary") var binaryPath = flag.String("binary", "../../out/minikube", "path to minikube binary")
var globalArgs = flag.String("minikube-args", "", "Arguments to pass to minikube") var globalArgs = flag.String("minikube-args", "", "Arguments to pass to minikube")
var startArgs = flag.String("minikube-start-args", "", "Arguments to pass to minikube start") var startArgs = flag.String("minikube-start-args", "", "Arguments to pass to minikube start")
@ -45,10 +45,10 @@ func NewMinikubeRunner(t *testing.T, profile string, extraStartArgs ...string) u
return util.MinikubeRunner{ return util.MinikubeRunner{
Profile: profile, Profile: profile,
BinaryPath: *binaryPath, BinaryPath: *binaryPath,
StartArgs: *startArgs + " " + strings.Join(extraStartArgs, " "), StartArgs: *startArgs + " --wait-timeout=13m " + strings.Join(extraStartArgs, " "), // adding timeout per component
GlobalArgs: *globalArgs, GlobalArgs: *globalArgs,
MountArgs: *mountArgs, MountArgs: *mountArgs,
TimeOutStart: time.Duration(*startTimeout) * time.Minute, TimeOutStart: *startTimeout, // timeout for all start
T: t, T: t,
} }
} }
@ -73,7 +73,7 @@ func profileName(t *testing.T) string {
return p return p
} }
// shouldRunInParallel deterimines if test should run in parallel or not // shouldRunInParallel determines if test should run in parallel or not
func shouldRunInParallel(t *testing.T) bool { func shouldRunInParallel(t *testing.T) bool {
t.Helper() t.Helper()
if !*parallel { if !*parallel {

View File

@ -34,8 +34,7 @@ import (
retryablehttp "github.com/hashicorp/go-retryablehttp" retryablehttp "github.com/hashicorp/go-retryablehttp"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
commonutil "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/kapi"
pkgutil "k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/retry" "k8s.io/minikube/pkg/util/retry"
"k8s.io/minikube/test/integration/util" "k8s.io/minikube/test/integration/util"
) )
@ -43,12 +42,12 @@ import (
func testAddons(t *testing.T) { func testAddons(t *testing.T) {
t.Parallel() t.Parallel()
p := profileName(t) p := profileName(t)
client, err := pkgutil.GetClient(p) client, err := kapi.Client(p)
if err != nil { if err != nil {
t.Fatalf("Could not get kubernetes client: %v", err) t.Fatalf("Could not get kubernetes client: %v", err)
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"component": "kube-addon-manager"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"component": "kube-addon-manager"}))
if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
t.Errorf("Error waiting for addon manager to be up") t.Errorf("Error waiting for addon manager to be up")
} }
} }
@ -193,22 +192,22 @@ func testRegistry(t *testing.T) {
p := profileName(t) p := profileName(t)
mk := NewMinikubeRunner(t, p) mk := NewMinikubeRunner(t, p)
mk.RunCommand("addons enable registry", true) mk.RunCommand("addons enable registry", true)
client, err := pkgutil.GetClient(p) client, err := kapi.Client(p)
if err != nil { if err != nil {
t.Fatalf("getting kubernetes client: %v", err) t.Fatalf("getting kubernetes client: %v", err)
} }
if err := pkgutil.WaitForRCToStabilize(client, "kube-system", "registry", time.Minute*5); err != nil { if err := kapi.WaitForRCToStabilize(client, "kube-system", "registry", time.Minute*5); err != nil {
t.Fatalf("waiting for registry replicacontroller to stabilize: %v", err) t.Fatalf("waiting for registry replicacontroller to stabilize: %v", err)
} }
rs := labels.SelectorFromSet(labels.Set(map[string]string{"actual-registry": "true"})) rs := labels.SelectorFromSet(labels.Set(map[string]string{"actual-registry": "true"}))
if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", rs); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "kube-system", rs); err != nil {
t.Fatalf("waiting for registry pods: %v", err) t.Fatalf("waiting for registry pods: %v", err)
} }
ps, err := labels.Parse("kubernetes.io/minikube-addons=registry,actual-registry!=true") ps, err := labels.Parse("kubernetes.io/minikube-addons=registry,actual-registry!=true")
if err != nil { if err != nil {
t.Fatalf("Unable to parse selector: %v", err) t.Fatalf("Unable to parse selector: %v", err)
} }
if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", ps); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "kube-system", ps); err != nil {
t.Fatalf("waiting for registry-proxy pods: %v", err) t.Fatalf("waiting for registry-proxy pods: %v", err)
} }
ip, stderr := mk.RunCommand("ip", true) ip, stderr := mk.RunCommand("ip", true)
@ -265,18 +264,18 @@ func testRegistry(t *testing.T) {
// waitForNginxRunning waits for nginx service to be up // waitForNginxRunning waits for nginx service to be up
func waitForNginxRunning(t *testing.T, miniProfile string) error { func waitForNginxRunning(t *testing.T, miniProfile string) error {
client, err := commonutil.GetClient(miniProfile) client, err := kapi.Client(miniProfile)
if err != nil { if err != nil {
return errors.Wrap(err, "getting kubernetes client") return errors.Wrap(err, "getting kubernetes client")
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"}))
if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "default", selector); err != nil {
return errors.Wrap(err, "waiting for nginx pods") return errors.Wrap(err, "waiting for nginx pods")
} }
if err := commonutil.WaitForService(client, "default", "nginx", true, time.Millisecond*500, time.Minute*10); err != nil { if err := kapi.WaitForService(client, "default", "nginx", true, time.Millisecond*500, time.Minute*10); err != nil {
t.Errorf("Error waiting for nginx service to be up") t.Errorf("Error waiting for nginx service to be up")
} }
return nil return nil
@ -284,17 +283,17 @@ func waitForNginxRunning(t *testing.T, miniProfile string) error {
// waitForIngressControllerRunning waits until ingress controller pod to be running // waitForIngressControllerRunning waits until ingress controller pod to be running
func waitForIngressControllerRunning(miniProfile string) error { func waitForIngressControllerRunning(miniProfile string) error {
client, err := commonutil.GetClient(miniProfile) client, err := kapi.Client(miniProfile)
if err != nil { if err != nil {
return errors.Wrap(err, "getting kubernetes client") return errors.Wrap(err, "getting kubernetes client")
} }
if err := commonutil.WaitForDeploymentToStabilize(client, "kube-system", "nginx-ingress-controller", time.Minute*10); err != nil { if err := kapi.WaitForDeploymentToStabilize(client, "kube-system", "nginx-ingress-controller", time.Minute*10); err != nil {
return errors.Wrap(err, "waiting for ingress-controller deployment to stabilize") return errors.Wrap(err, "waiting for ingress-controller deployment to stabilize")
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"app.kubernetes.io/name": "nginx-ingress-controller"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"app.kubernetes.io/name": "nginx-ingress-controller"}))
if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
return errors.Wrap(err, "waiting for ingress-controller pods") return errors.Wrap(err, "waiting for ingress-controller pods")
} }

View File

@ -26,7 +26,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
pkgutil "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/util/retry" "k8s.io/minikube/pkg/util/retry"
"k8s.io/minikube/test/integration/util" "k8s.io/minikube/test/integration/util"
) )
@ -34,7 +34,7 @@ import (
func testClusterDNS(t *testing.T) { func testClusterDNS(t *testing.T) {
t.Parallel() t.Parallel()
p := profileName(t) p := profileName(t)
client, err := pkgutil.GetClient(p) client, err := kapi.Client(p)
if err != nil { if err != nil {
t.Fatalf("Error getting kubernetes client %v", err) t.Fatalf("Error getting kubernetes client %v", err)
} }

View File

@ -29,7 +29,7 @@ import (
"time" "time"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
pkgutil "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/util/lock" "k8s.io/minikube/pkg/util/lock"
"k8s.io/minikube/pkg/util/retry" "k8s.io/minikube/pkg/util/retry"
"k8s.io/minikube/test/integration/util" "k8s.io/minikube/test/integration/util"
@ -132,12 +132,12 @@ func writeFilesFromHost(mountedDir string, files []string, content string) error
} }
func waitForPods(s map[string]string, profile string) error { func waitForPods(s map[string]string, profile string) error {
client, err := pkgutil.GetClient(profile) client, err := kapi.Client(profile)
if err != nil { if err != nil {
return fmt.Errorf("getting kubernetes client: %v", err) return fmt.Errorf("getting kubernetes client: %v", err)
} }
selector := labels.SelectorFromSet(labels.Set(s)) selector := labels.SelectorFromSet(labels.Set(s))
if err := pkgutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "default", selector); err != nil {
return err return err
} }
return nil return nil

View File

@ -29,7 +29,7 @@ import (
core "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
commonutil "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/util/retry" "k8s.io/minikube/pkg/util/retry"
"k8s.io/minikube/test/integration/util" "k8s.io/minikube/test/integration/util"
) )
@ -73,13 +73,13 @@ func testProvisioning(t *testing.T) {
// Check that the storage provisioner pod is running // Check that the storage provisioner pod is running
checkPodRunning := func() error { checkPodRunning := func() error {
client, err := commonutil.GetClient(p) client, err := kapi.Client(p)
if err != nil { if err != nil {
return errors.Wrap(err, "getting kubernetes client") return errors.Wrap(err, "getting kubernetes client")
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "storage-provisioner"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "storage-provisioner"}))
if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
return err return err
} }
return nil return nil

View File

@ -31,8 +31,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/minikube/tunnel" "k8s.io/minikube/pkg/minikube/tunnel"
commonutil "k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/retry" "k8s.io/minikube/pkg/util/retry"
"k8s.io/minikube/test/integration/util" "k8s.io/minikube/test/integration/util"
) )
@ -70,18 +70,18 @@ func testTunnel(t *testing.T) {
t.Fatalf("creating nginx ingress resource: %s", err) t.Fatalf("creating nginx ingress resource: %s", err)
} }
client, err := commonutil.GetClient(p) client, err := kapi.Client(p)
if err != nil { if err != nil {
t.Fatal(errors.Wrap(err, "getting kubernetes client")) t.Fatal(errors.Wrap(err, "getting kubernetes client"))
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx-svc"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx-svc"}))
if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { if err := kapi.WaitForPodsWithLabelRunning(client, "default", selector); err != nil {
t.Fatal(errors.Wrap(err, "waiting for nginx pods")) t.Fatal(errors.Wrap(err, "waiting for nginx pods"))
} }
if err := commonutil.WaitForService(client, "default", "nginx-svc", true, 1*time.Second, 2*time.Minute); err != nil { if err := kapi.WaitForService(client, "default", "nginx-svc", true, 1*time.Second, 2*time.Minute); err != nil {
t.Fatal(errors.Wrap(err, "Error waiting for nginx service to be up")) t.Fatal(errors.Wrap(err, "Error waiting for nginx service to be up"))
} }
@ -114,14 +114,14 @@ func testTunnel(t *testing.T) {
func getIngress(kr *util.KubectlRunner) (string, error) { func getIngress(kr *util.KubectlRunner) (string, error) {
nginxIP := "" nginxIP := ""
var ret error var ret error
err := wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { err := wait.PollImmediate(1*time.Second, 2*time.Minute, func() (bool, error) {
cmd := []string{"get", "svc", "nginx-svc", "-o", "jsonpath={.status.loadBalancer.ingress[0].ip}"} cmd := []string{"get", "svc", "nginx-svc", "-o", "jsonpath={.status.loadBalancer.ingress[0].ip}"}
stdout, err := kr.RunCommand(cmd) stdout, err := kr.RunCommand(cmd)
switch { switch {
case err == nil: case err == nil:
nginxIP = string(stdout) nginxIP = string(stdout)
return len(stdout) != 0, nil return len(stdout) != 0, nil
case !commonutil.IsRetryableAPIError(err): case !kapi.IsRetryableAPIError(err):
ret = fmt.Errorf("`%s` failed with non retriable error: %v", cmd, err) ret = fmt.Errorf("`%s` failed with non retriable error: %v", cmd, err)
return false, err return false, err
default: default:

View File

@ -27,6 +27,8 @@ import (
"strings" "strings"
"syscall" "syscall"
"testing" "testing"
"k8s.io/minikube/pkg/minikube/constants"
) )
func TestNone(t *testing.T) { func TestNone(t *testing.T) {
@ -76,7 +78,7 @@ func testNoneMinikubeFolderPermissions(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to convert uid to int: %v", err) t.Errorf("Failed to convert uid to int: %v", err)
} }
info, err := os.Stat(filepath.Join(u.HomeDir, ".minikube")) info, err := os.Stat(constants.GetMinipath())
if err != nil { if err != nil {
t.Fatalf("Failed to get .minikube dir info, %v", err) t.Fatalf("Failed to get .minikube dir info, %v", err)
} }

View File

@ -23,17 +23,17 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
commonutil "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/kapi"
) )
// WaitForBusyboxRunning waits until busybox pod to be running // WaitForBusyboxRunning waits until busybox pod to be running
func WaitForBusyboxRunning(t *testing.T, namespace string, miniProfile string) error { func WaitForBusyboxRunning(t *testing.T, namespace string, miniProfile string) error {
client, err := commonutil.GetClient(miniProfile) client, err := kapi.Client(miniProfile)
if err != nil { if err != nil {
return errors.Wrap(err, "getting kubernetes client") return errors.Wrap(err, "getting kubernetes client")
} }
selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox"})) selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox"}))
return commonutil.WaitForPodsWithLabelRunning(client, namespace, selector) return kapi.WaitForPodsWithLabelRunning(client, namespace, selector)
} }
// Logf writes logs to stdout if -v is set. // Logf writes logs to stdout if -v is set.

View File

@ -124,7 +124,7 @@ func (m *MinikubeRunner) RunCommand(cmdStr string, failError bool, waitForRun ..
return stdout, stderr return stdout, stderr
} }
// RunCommandRetriable Error executes a command, returns error // RunCommandRetriable executes a command, returns error
// the purpose of this command is to make it retriable and // the purpose of this command is to make it retriable and
// better logging for retrying // better logging for retrying
func (m *MinikubeRunner) RunCommandRetriable(cmdStr string, waitForRun ...bool) (stdout string, stderr string, err error) { func (m *MinikubeRunner) RunCommandRetriable(cmdStr string, waitForRun ...bool) (stdout string, stderr string, err error) {
@ -244,7 +244,7 @@ func (m *MinikubeRunner) TearDown(t *testing.T) {
profileArg := fmt.Sprintf("-p=%s", m.Profile) profileArg := fmt.Sprintf("-p=%s", m.Profile)
path, _ := filepath.Abs(m.BinaryPath) path, _ := filepath.Abs(m.BinaryPath)
cmd := exec.Command(path, profileArg, "delete") cmd := exec.Command(path, profileArg, "delete")
err := cmd.Start() err := cmd.Start() // don't wait for it to finish
if err != nil { if err != nil {
t.Errorf("error tearing down minikube %s : %v", profileArg, err) t.Errorf("error tearing down minikube %s : %v", profileArg, err)
} }

View File

@ -73,10 +73,14 @@ func TestVersionUpgrade(t *testing.T) {
} }
defer os.Remove(fname) defer os.Remove(fname)
mkCurrent := NewMinikubeRunner(t, p) mkHead := NewMinikubeRunner(t, p) // minikube from HEAD.
defer mkCurrent.TearDown(t) defer mkHead.TearDown(t)
mkRelease := NewMinikubeRunner(t, p) mkRelease := NewMinikubeRunner(t, p) // lastest publicly released version minikbue.
// because the --wait-timeout is a new flag and the current latest release (1.3.1) doesn't have it
// this won't be necessary after we release the change with --wait-timeout flag
mkRelease.StartArgs = strings.Replace("mkRelease.StartArgs", "--wait-timeout=13m", "", 1)
mkRelease.BinaryPath = fname mkRelease.BinaryPath = fname
// For full coverage: also test upgrading from oldest to newest supported k8s release // For full coverage: also test upgrading from oldest to newest supported k8s release
stdout, stderr, err := mkRelease.Start(fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion)) stdout, stderr, err := mkRelease.Start(fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion))
@ -89,9 +93,9 @@ func TestVersionUpgrade(t *testing.T) {
mkRelease.CheckStatus(state.Stopped.String()) mkRelease.CheckStatus(state.Stopped.String())
// Trim the leading "v" prefix to assert that we handle it properly. // Trim the leading "v" prefix to assert that we handle it properly.
stdout, stderr, err = mkCurrent.Start(fmt.Sprintf("--kubernetes-version=%s", strings.TrimPrefix(constants.NewestKubernetesVersion, "v"))) stdout, stderr, err = mkHead.Start(fmt.Sprintf("--kubernetes-version=%s", strings.TrimPrefix(constants.NewestKubernetesVersion, "v")))
if err != nil { if err != nil {
t.Fatalf("TestVersionUpgrade mkCurrent.Start start failed : %v\nstdout: %s\nstderr: %s", err, stdout, stderr) t.Fatalf("TestVersionUpgrade mkCurrent.Start start failed : %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
} }
mkCurrent.CheckStatus(state.Running.String()) mkHead.CheckStatus(state.Running.String())
} }