Merge branch 'master' of github.com:kubernetes/minikube into compare

pull/5678/head
Priya Wadhwa 2019-12-19 11:28:11 -08:00
commit 48b5a1e493
77 changed files with 1193 additions and 459 deletions

View File

@ -1,5 +1,69 @@
# Release Notes
## Version 1.6.1 - 2019-12-11
A special bugfix release to fix a Windows regression:
* lock names: Remove uid suffix & hash entire path [#6059](https://github.com/kubernetes/minikube/pull/6059)
## Version 1.6.0 - 2019-12-10
* Update default k8s version to v1.17.0 [#6042](https://github.com/kubernetes/minikube/pull/6042)
* Make Kubernetes version sticky for a cluster instead of auto-upgrading [#5798](https://github.com/kubernetes/minikube/pull/5798)
* cache add: load images to all profiles & skip previously cached images [#5987](https://github.com/kubernetes/minikube/pull/5987)
* Update dashboard to 2.0.0b8 and pre-cache it again [#6039](https://github.com/kubernetes/minikube/pull/6039)
* Pre-cache the latest kube-addon-manager [#5935](https://github.com/kubernetes/minikube/pull/5935)
* Add sch_netem kernel module for network emulation [#6038](https://github.com/kubernetes/minikube/pull/6038)
* Don't use bash as the entrypoint for docker [#5818](https://github.com/kubernetes/minikube/pull/5818)
* Make lock names uid and path specific to avoid conflicts [#5912](https://github.com/kubernetes/minikube/pull/5912)
* Remove deprecated annotation storageclass.beta.kubernetes.io [#5954](https://github.com/kubernetes/minikube/pull/5954)
* show status in profile list [#5988](https://github.com/kubernetes/minikube/pull/5988)
* Use newer gvisor version [#6000](https://github.com/kubernetes/minikube/pull/6000)
* Adds dm-crypt support [#5739](https://github.com/kubernetes/minikube/pull/5739)
* Add performance analysis packages to minikube ISO [#5942](https://github.com/kubernetes/minikube/pull/5942)
Thanks goes out to the merry band of Kubernetes contributors that made this release possible:
- Anders F Björklund
- Anukul Sangwan
- Guilherme Pellizzetti
- Jan Ahrens
- Karuppiah Natarajan
- Laura-Marie Henning
- Medya Ghazizadeh
- Nanik T
- Olivier Lemasle
- Priya Wadhwa
- Sharif Elgamal
- Thomas Strömberg
- Vasyl Purchel
- Wietse Muizelaar
## Version 1.6.0-beta.1 - 2019-11-26
* cri-o v1.16.0 [#5970](https://github.com/kubernetes/minikube/pull/5970)
* Update default k8s version to 1.17.0-rc.1 [#5973](https://github.com/kubernetes/minikube/pull/5973)
* Update crictl to v1.16.1 [#5972](https://github.com/kubernetes/minikube/pull/5972)
* Update docker to v19.03.5 [#5914](https://github.com/kubernetes/minikube/pull/5914)
* Fix profile list for non existenting folder [#5955](https://github.com/kubernetes/minikube/pull/5955)
* Upgrade podman to 1.6.3 [#5971](https://github.com/kubernetes/minikube/pull/5971)
* Fix validation of container-runtime config [#5964](https://github.com/kubernetes/minikube/pull/5964)
* Add option for virtualbox users to set nat-nic-type [#5960](https://github.com/kubernetes/minikube/pull/5960)
* Upgrade buildroot minor version to 2019.02.7 [#5967](https://github.com/kubernetes/minikube/pull/5967)
* dashboard: Update to latest images (2.0.0-beta6) [#5934](https://github.com/kubernetes/minikube/pull/5934)
Huge thank you for this release towards our contributors:
- Adam Crowder
- Anders F Björklund
- David Newman
- Harsimran Singh Maan
- Kenta Iso
- Medya Ghazizadeh
- Reuven Harrison
- Sharif Elgamal
- Thomas Stromberg
- yuxiaobo
## Version 1.6.0-beta.0 - 2019-11-15
* Update DefaultKubernetesVersion to v1.17.0-beta.1 to prepare for betas [#5925](https://github.com/kubernetes/minikube/pull/5925)
@ -30,7 +94,6 @@ Huge thank you for this release towards our contributors:
- Steffen Gransow
- Thomas Strömberg
## Version 1.5.2 - 2019-10-31 (Happy Halloween!)
* service: fix --url mode [#5790](https://github.com/kubernetes/minikube/pull/5790)

View File

@ -15,12 +15,12 @@
# Bump these on release - and please check ISO_VERSION for correctness.
VERSION_MAJOR ?= 1
VERSION_MINOR ?= 6
VERSION_BUILD ?= 0-beta.0
VERSION_BUILD ?= 1
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 ?= v1.5.1
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)
@ -60,7 +60,8 @@ GOLINT_GOGC ?= 100
GOLINT_OPTIONS = --timeout 4m \
--build-tags "${MINIKUBE_INTEGRATION_BUILD_TAGS}" \
--enable goimports,gocritic,golint,gocyclo,misspell,nakedret,stylecheck,unconvert,unparam,dogsled \
--exclude 'variable on range scope.*in function literal|ifElseChain'
--exclude 'variable on range scope.*in function literal|ifElseChain' \
--skip-files "pkg/minikube/translate/translations.go|pkg/minikube/assets/assets.go"
# Major version of gvisor image. Increment when there are breaking changes.
GVISOR_IMAGE_VERSION ?= 2
@ -118,7 +119,7 @@ HYPERKIT_LDFLAGS := -X k8s.io/minikube/pkg/drivers/hyperkit.version=$(VERSION) -
# $(call DOCKER, image, command)
define DOCKER
docker run --rm -e GOCACHE=/app/.cache -e IN_DOCKER=1 --user $(shell id -u):$(shell id -g) -w /app -v $(PWD):/app -v $(GOPATH):/go --entrypoint /bin/bash $(1) -c '$(2)'
docker run --rm -e GOCACHE=/app/.cache -e IN_DOCKER=1 --user $(shell id -u):$(shell id -g) -w /app -v $(PWD):/app -v $(GOPATH):/go --init $(1) /bin/bash -c '$(2)'
endef
ifeq ($(BUILD_IN_DOCKER),y)
@ -436,7 +437,10 @@ out/minikube-installer.exe: out/minikube-windows-amd64.exe
out/docker-machine-driver-hyperkit:
ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y)
$(call DOCKER,$(HYPERKIT_BUILD_IMAGE),CC=o64-clang CXX=o64-clang++ /usr/bin/make $@)
docker run --rm -e GOCACHE=/app/.cache -e IN_DOCKER=1 \
--user $(shell id -u):$(shell id -g) -w /app \
-v $(PWD):/app -v $(GOPATH):/go --init --entrypoint "" \
$(HYPERKIT_BUILD_IMAGE) /bin/bash -c 'CC=o64-clang CXX=o64-clang++ /usr/bin/make $@'
else
GOOS=darwin CGO_ENABLED=1 go build \
-ldflags="$(HYPERKIT_LDFLAGS)" \
@ -445,7 +449,7 @@ endif
hyperkit_in_docker:
rm -f out/docker-machine-driver-hyperkit
$(call DOCKER,$(HYPERKIT_BUILD_IMAGE),CC=o64-clang CXX=o64-clang++ /usr/bin/make out/docker-machine-driver-hyperkit)
$(MAKE) MINIKUBE_BUILD_IN_DOCKER=y out/docker-machine-driver-hyperkit
.PHONY: install-hyperkit-driver
install-hyperkit-driver: out/docker-machine-driver-hyperkit ## Install hyperkit to local machine
@ -582,7 +586,11 @@ site: site/themes/docsy/assets/vendor/bootstrap/package.js out/hugo/hugo ## Serv
.PHONY: out/mkcmp
out/mkcmp:
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/main.go
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/mkcmp/main.go
.PHONY: out/performance-monitor
out/performance-monitor:
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/monitor/monitor.go
.PHONY: compare
compare: out/mkcmp out/minikube

View File

@ -76,7 +76,7 @@ var ProfileCmd = &cobra.Command{
if err != nil {
exit.WithError("Setting profile failed", err)
}
cc, err := pkgConfig.Load()
cc, err := pkgConfig.Load(profile)
// might err when loading older version of cfg file that doesn't have KeepContext field
if err != nil && !os.IsNotExist(err) {
out.ErrT(out.Sad, `Error loading profile config: {{.error}}`, out.V{"error": err})

View File

@ -23,10 +23,13 @@ import (
"strconv"
"strings"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/out"
"github.com/golang/glog"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
)
@ -58,7 +61,7 @@ var printProfilesTable = func() {
var validData [][]string
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Profile", "VM Driver", "NodeIP", "Node Port", "Kubernetes Version"})
table.SetHeader([]string{"Profile", "VM Driver", "NodeIP", "Node Port", "Kubernetes Version", "Status"})
table.SetAutoFormatHeaders(false)
table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true})
table.SetCenterSeparator("|")
@ -67,8 +70,18 @@ var printProfilesTable = func() {
if len(validProfiles) == 0 || err != nil {
exit.UsageT("No minikube profile was found. You can create one using `minikube start`.")
}
api, err := machine.NewAPIClient()
if err != nil {
glog.Infof("failed to get machine api client %v", err)
}
defer api.Close()
for _, p := range validProfiles {
validData = append(validData, []string{p.Name, p.Config[0].VMDriver, p.Config[0].KubernetesConfig.NodeIP, strconv.Itoa(p.Config[0].KubernetesConfig.NodePort), p.Config[0].KubernetesConfig.KubernetesVersion})
p.Status, err = cluster.GetHostStatus(api, p.Name)
if err != nil {
glog.Infof("error getting host status for %v", err)
}
validData = append(validData, []string{p.Name, p.Config[0].VMDriver, p.Config[0].KubernetesConfig.NodeIP, strconv.Itoa(p.Config[0].KubernetesConfig.NodePort), p.Config[0].KubernetesConfig.KubernetesVersion, p.Status})
}
table.AppendBulk(validData)
@ -93,7 +106,20 @@ var printProfilesTable = func() {
}
var printProfilesJSON = func() {
api, err := machine.NewAPIClient()
if err != nil {
glog.Infof("failed to get machine api client %v", err)
}
defer api.Close()
validProfiles, invalidProfiles, err := config.ListProfiles()
for _, v := range validProfiles {
status, err := cluster.GetHostStatus(api, v.Name)
if err != nil {
glog.Infof("error getting host status for %v", err)
}
v.Status = status
}
var valid []*config.Profile
var invalid []*config.Profile

View File

@ -23,6 +23,7 @@ import (
"strings"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/command"
@ -137,7 +138,7 @@ func EnableOrDisableAddon(name string, val string) error {
return nil
}
cfg, err := config.Load()
cfg, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil && !os.IsNotExist(err) {
exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err})
}

View File

@ -122,17 +122,16 @@ func TestValidateProfile(t *testing.T) {
profileName: "82374328742_2974224498",
},
{
profileName: "minikube",
profileName: "validate_test",
},
}
for _, test := range testCases {
profileNam := test.profileName
expectedMsg := fmt.Sprintf("profile %q not found", test.profileName)
expected := fmt.Sprintf("profile %q not found", test.profileName)
err, ok := ValidateProfile(profileNam)
if !ok && err.Error() != expectedMsg {
t.Errorf("Didnt receive expected message")
if !ok && err.Error() != expected {
t.Errorf("got error %q, expected %q", err, expected)
}
}
}

View File

@ -26,6 +26,7 @@ import (
units "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/cruntime"
@ -158,7 +159,7 @@ func IsValidRuntime(name string, runtime string) error {
// IsContainerdRuntime is a validator which returns an error if the current runtime is not containerd
func IsContainerdRuntime(_, _ string) error {
config, err := config.Load()
config, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
return fmt.Errorf("config.Load: %v", err)
}

View File

@ -32,9 +32,11 @@ import (
"github.com/pkg/browser"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
configcmd "k8s.io/minikube/cmd/minikube/cmd/config"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
pkg_config "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
@ -57,7 +59,7 @@ var dashboardCmd = &cobra.Command{
Short: "Access the kubernetes dashboard running within the minikube cluster",
Long: `Access the kubernetes dashboard running within the minikube cluster`,
Run: func(cmd *cobra.Command, args []string) {
cc, err := pkg_config.Load()
cc, err := pkg_config.Load(viper.GetString(config.MachineProfile))
if err != nil && !os.IsNotExist(err) {
exit.WithError("Error loading profile config", err)
}

View File

@ -163,7 +163,7 @@ func DeleteProfiles(profiles []*pkg_config.Profile) []error {
err := deleteProfile(profile)
if err != nil {
mm, loadErr := cluster.LoadMachine(profile.Name)
mm, loadErr := machine.Load(profile.Name)
if !profile.IsValid() || (loadErr != nil || !mm.IsValid()) {
invalidProfileDeletionErrs := deleteInvalidProfile(profile)
@ -187,8 +187,7 @@ func deleteProfile(profile *pkg_config.Profile) error {
return DeletionError{Err: delErr, Errtype: Fatal}
}
defer api.Close()
cc, err := pkg_config.Load()
cc, err := pkg_config.Load(profile.Name)
if err != nil && !os.IsNotExist(err) {
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("error loading profile config: %v", err))
return DeletionError{Err: delErr, Errtype: MissingProfile}
@ -263,7 +262,7 @@ func deleteInvalidProfile(profile *pkg_config.Profile) []error {
}
}
pathToMachine := cluster.MachinePath(profile.Name, localpath.MiniPath())
pathToMachine := localpath.MachinePath(profile.Name, localpath.MiniPath())
if _, err := os.Stat(pathToMachine); !os.IsNotExist(err) {
err := os.RemoveAll(pathToMachine)
if err != nil {

View File

@ -26,7 +26,6 @@ import (
"github.com/otiai10/copy"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/localpath"
)
@ -117,7 +116,7 @@ func TestDeleteProfile(t *testing.T) {
t.Errorf("Profile folder of profile \"%s\" was not deleted", profile.Name)
}
pathToMachine := cluster.MachinePath(profile.Name, localpath.MiniPath())
pathToMachine := localpath.MachinePath(profile.Name, localpath.MiniPath())
if _, err := os.Stat(pathToMachine); !os.IsNotExist(err) {
t.Errorf("Profile folder of profile \"%s\" was not deleted", profile.Name)
}

View File

@ -340,7 +340,7 @@ var dockerEnvCmd = &cobra.Command{
exit.WithError("Error getting client", err)
}
defer api.Close()
cc, err := config.Load()
cc, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Error getting config", err)
}

View File

@ -20,6 +20,7 @@ import (
"github.com/docker/machine/libmachine/mcnerror"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
@ -38,7 +39,7 @@ var ipCmd = &cobra.Command{
}
defer api.Close()
cc, err := config.Load()
cc, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Error getting config", err)
}

View File

@ -25,6 +25,8 @@ import (
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/config"
pkg_config "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/exit"
@ -48,7 +50,7 @@ kubectl get pods --namespace kube-system`,
}
defer api.Close()
cc, err := pkg_config.Load()
cc, err := pkg_config.Load(viper.GetString(config.MachineProfile))
if err != nil && !os.IsNotExist(err) {
out.ErrLn("Error loading profile config: %v", err)
}

View File

@ -47,7 +47,7 @@ var logsCmd = &cobra.Command{
Short: "Gets the logs of the running instance, used for debugging minikube, not user code.",
Long: `Gets the logs of the running instance, used for debugging minikube, not user code.`,
Run: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
cfg, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Error getting config", err)
}

View File

@ -29,6 +29,7 @@ import (
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
@ -102,7 +103,7 @@ var mountCmd = &cobra.Command{
exit.WithError("Error getting client", err)
}
defer api.Close()
cc, err := config.Load()
cc, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Error getting config", err)
}

View File

@ -20,6 +20,7 @@ import (
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
@ -32,7 +33,7 @@ var sshKeyCmd = &cobra.Command{
Short: "Retrieve the ssh identity key path of the specified cluster",
Long: "Retrieve the ssh identity key path of the specified cluster.",
Run: func(cmd *cobra.Command, args []string) {
cc, err := config.Load()
cc, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Getting machine config failed", err)
}

View File

@ -42,7 +42,7 @@ var sshCmd = &cobra.Command{
exit.WithError("Error getting client", err)
}
defer api.Close()
cc, err := config.Load()
cc, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Error getting config", err)
}

View File

@ -51,6 +51,7 @@ import (
"k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/config"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/cruntime"
@ -180,7 +181,7 @@ func initMinikubeFlags() {
// initKubernetesFlags inits the commandline flags for kubernetes related options
func initKubernetesFlags() {
startCmd.Flags().String(kubernetesVersion, constants.DefaultKubernetesVersion, "The kubernetes version that the minikube VM will use (ex: v1.2.3)")
startCmd.Flags().String(kubernetesVersion, "", "The kubernetes version that the minikube VM will use (ex: v1.2.3)")
startCmd.Flags().Var(&extraOptions, "extra-config",
`A set of key=value pairs that describe configuration that may be passed to different components.
The key should be '.' separated, and the first part before the dot is the component to apply the configuration to.
@ -287,7 +288,7 @@ func runStart(cmd *cobra.Command, args []string) {
registryMirror = viper.GetStringSlice("registry_mirror")
}
existing, err := cfg.Load()
existing, err := cfg.Load(viper.GetString(config.MachineProfile))
if err != nil && !os.IsNotExist(err) {
exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err})
}
@ -352,7 +353,7 @@ func runStart(cmd *cobra.Command, args []string) {
}
// setup kubeadm (must come after setupKubeconfig)
bs := setupKubeAdm(machineAPI, config.KubernetesConfig)
bs := setupKubeAdm(machineAPI, config)
// pull images or restart cluster
bootstrapCluster(bs, cr, mRunner, config.KubernetesConfig, preExists, isUpgrade)
@ -645,7 +646,7 @@ func validateDriver(name string, existing *cfg.MachineConfig) {
exit.WithCodeT(exit.Config, "Exiting.")
}
func selectImageRepository(mirrorCountry string, k8sVersion string) (bool, string, error) {
func selectImageRepository(mirrorCountry string) (bool, string, error) {
var tryCountries []string
var fallback string
glog.Infof("selecting image repository for country %s ...", mirrorCountry)
@ -673,7 +674,7 @@ func selectImageRepository(mirrorCountry string, k8sVersion string) (bool, strin
}
checkRepository := func(repo string) error {
pauseImage := images.PauseImage(repo, k8sVersion)
pauseImage := images.Pause(repo)
ref, err := name.ParseReference(pauseImage, name.WeakValidation)
if err != nil {
return err
@ -729,7 +730,7 @@ func validateUser(drvName string) {
if !useForce {
os.Exit(exit.Permissions)
}
_, err = cfg.Load()
_, err = cfg.Load(viper.GetString(config.MachineProfile))
if err == nil || !os.IsNotExist(err) {
out.T(out.Tip, "Tip: To remove this root owned cluster, run: sudo {{.cmd}} delete", out.V{"cmd": minikubeCmd()})
}
@ -866,7 +867,7 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string)
repository := viper.GetString(imageRepository)
mirrorCountry := strings.ToLower(viper.GetString(imageMirrorCountry))
if strings.ToLower(repository) == "auto" || mirrorCountry != "" {
found, autoSelectedRepository, err := selectImageRepository(mirrorCountry, k8sVersion)
found, autoSelectedRepository, err := selectImageRepository(mirrorCountry)
if err != nil {
exit.WithError("Failed to check main repository and mirrors for images for images", err)
}
@ -1108,7 +1109,7 @@ func tryRegistry(r command.Runner) {
repo := viper.GetString(imageRepository)
if repo == "" {
repo = images.DefaultImageRepo
repo = images.DefaultKubernetesRepo
}
opts = append(opts, fmt.Sprintf("https://%s/", repo))
@ -1120,15 +1121,20 @@ func tryRegistry(r command.Runner) {
// getKubernetesVersion ensures that the requested version is reasonable
func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
rawVersion := viper.GetString(kubernetesVersion)
paramVersion := viper.GetString(kubernetesVersion)
isUpgrade := false
if rawVersion == "" {
rawVersion = constants.DefaultKubernetesVersion
if paramVersion == "" { // if the user did not specify any version then ...
if old != nil { // .. use the old version from config
paramVersion = old.KubernetesConfig.KubernetesVersion
} else { // .. otherwise use the default version
paramVersion = constants.DefaultKubernetesVersion
}
}
nvs, err := semver.Make(strings.TrimPrefix(rawVersion, version.VersionPrefix))
nvs, err := semver.Make(strings.TrimPrefix(paramVersion, version.VersionPrefix))
if err != nil {
exit.WithCodeT(exit.Data, `Unable to parse "{{.kubernetes_version}}": {{.error}}`, out.V{"kubernetes_version": rawVersion, "error": err})
exit.WithCodeT(exit.Data, `Unable to parse "{{.kubernetes_version}}": {{.error}}`, out.V{"kubernetes_version": paramVersion, "error": err})
}
nv := version.VersionPrefix + nvs.String()
@ -1140,6 +1146,10 @@ func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
if err != nil {
exit.WithCodeT(exit.Data, "Unable to parse oldest Kubernetes version from constants: {{.error}}", out.V{"error": err})
}
defaultVersion, err := semver.Make(strings.TrimPrefix(constants.DefaultKubernetesVersion, version.VersionPrefix))
if err != nil {
exit.WithCodeT(exit.Data, "Unable to parse default Kubernetes version from constants: {{.error}}", out.V{"error": err})
}
if nvs.LT(oldestVersion) {
out.WarningT("Specified Kubernetes version {{.specified}} is less than the oldest supported version: {{.oldest}}", out.V{"specified": nvs, "oldest": constants.OldestKubernetesVersion})
@ -1168,15 +1178,18 @@ func getKubernetesVersion(old *cfg.MachineConfig) (string, bool) {
* Reuse the existing cluster with Kubernetes v{{.old}} or newer: Run "minikube start {{.profile}} --kubernetes-version={{.old}}"`, out.V{"new": nvs, "old": ovs, "profile": profileArg})
}
if defaultVersion.GT(nvs) {
out.T(out.ThumbsUp, "Kubernetes {{.new}} is now available. If you would like to upgrade, specify: --kubernetes-version={{.new}}", out.V{"new": defaultVersion})
}
if nvs.GT(ovs) {
out.T(out.ThumbsUp, "Upgrading from Kubernetes {{.old}} to {{.new}}", out.V{"old": ovs, "new": nvs})
isUpgrade = true
}
return nv, isUpgrade
}
// setupKubeAdm adds any requested files into the VM before Kubernetes is started
func setupKubeAdm(mAPI libmachine.API, kc cfg.KubernetesConfig) bootstrapper.Bootstrapper {
func setupKubeAdm(mAPI libmachine.API, config cfg.MachineConfig) bootstrapper.Bootstrapper {
bs, err := getClusterBootstrapper(mAPI, viper.GetString(cmdcfg.Bootstrapper))
if err != nil {
exit.WithError("Failed to get bootstrapper", err)
@ -1185,10 +1198,10 @@ func setupKubeAdm(mAPI libmachine.API, kc cfg.KubernetesConfig) bootstrapper.Boo
out.T(out.Option, "{{.extra_option_component_name}}.{{.key}}={{.value}}", out.V{"extra_option_component_name": eo.Component, "key": eo.Key, "value": eo.Value})
}
// Loads cached images, generates config files, download binaries
if err := bs.UpdateCluster(kc); err != nil {
if err := bs.UpdateCluster(config); err != nil {
exit.WithError("Failed to update cluster", err)
}
if err := bs.SetupCerts(kc); err != nil {
if err := bs.SetupCerts(config.KubernetesConfig); err != nil {
exit.WithError("Failed to setup certs", err)
}
return bs

View File

@ -22,9 +22,64 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
)
func TestGetKuberneterVersion(t *testing.T) {
var tests = []struct {
description string
expectedVersion string
paramVersion string
upgrade bool
cfg *cfg.MachineConfig
}{
{
description: "kubernetes-version not given, no config",
expectedVersion: constants.DefaultKubernetesVersion,
paramVersion: "",
upgrade: false,
},
{
description: "kubernetes-version not given, config available",
expectedVersion: "v1.15.0",
paramVersion: "",
upgrade: false,
cfg: &cfg.MachineConfig{KubernetesConfig: cfg.KubernetesConfig{KubernetesVersion: "v1.15.0"}},
},
{
description: "kubernetes-version given, no config",
expectedVersion: "v1.15.0",
paramVersion: "v1.15.0",
upgrade: false,
},
{
description: "kubernetes-version given, config available",
expectedVersion: "v1.16.0",
paramVersion: "v1.16.0",
upgrade: true,
cfg: &cfg.MachineConfig{KubernetesConfig: cfg.KubernetesConfig{KubernetesVersion: "v1.15.0"}},
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
viper.SetDefault(kubernetesVersion, test.paramVersion)
version, upgrade := getKubernetesVersion(test.cfg)
// check whether we are getting the expected version
if version != test.expectedVersion {
t.Fatalf("test failed because the expected version %s is not returned", test.expectedVersion)
}
// check whether the upgrade flag is correct
if test.upgrade != upgrade {
t.Fatalf("test failed expected upgrade is %t", test.upgrade)
}
})
}
}
func TestGenerateCfgFromFlagsHTTPProxyHandling(t *testing.T) {
viper.SetDefault(memory, defaultMemorySize)
viper.SetDefault(humanReadableDiskSize, defaultDiskSize)

View File

@ -24,6 +24,7 @@ import (
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
@ -76,11 +77,11 @@ var tunnelCmd = &cobra.Command{
cancel()
}()
cc, err := config.Load()
cfg, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Error getting config", err)
}
done, err := manager.StartTunnel(ctx, cc.Name, api, config.DefaultLoader, clientset.CoreV1())
done, err := manager.StartTunnel(ctx, cfg.Name, api, config.DefaultLoader, clientset.CoreV1())
if err != nil {
exit.WithError("error starting tunnel", err)
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package cmd
import (
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/cluster"
@ -45,7 +47,13 @@ var updateContextCmd = &cobra.Command{
if err != nil {
exit.WithError("Error host driver ip status", err)
}
updated, err := kubeconfig.UpdateIP(ip, machineName, constants.KubeconfigPath)
updated := false
kubeConfigPath := os.Getenv("KUBECONFIG")
if kubeConfigPath == "" {
updated, err = kubeconfig.UpdateIP(ip, machineName, constants.KubeconfigPath)
} else {
updated, err = kubeconfig.UpdateIP(ip, machineName, kubeConfigPath)
}
if err != nil {
exit.WithError("update config", err)
}

View File

@ -16,7 +16,7 @@ limitations under the License.
package main
import "k8s.io/minikube/cmd/performance/cmd"
import "k8s.io/minikube/cmd/performance/mkcmp/cmd"
func main() {
cmd.Execute()

View File

@ -0,0 +1,40 @@
/*
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 (
"context"
"log"
"time"
)
func main() {
for {
if err := analyzePerformance(context.Background()); err != nil {
log.Printf("error executing performance analysis: %v", err)
}
time.Sleep(10 * time.Minute)
}
}
// analyzePerformance is responsible for:
// 1. collecting PRs to run performance analysis on
// 2. running mkcmp against those PRs
// 3. commenting results on those PRs
func analyzePerformance(ctx context.Context) error {
return nil
}

View File

@ -89,7 +89,8 @@ spec:
spec:
containers:
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.0.0-beta6
# WARNING: This must match pkg/minikube/bootstrapper/images/images.go
image: kubernetesui/dashboard:v2.0.0-beta8
ports:
- containerPort: 9090
protocol: TCP

View File

@ -95,7 +95,7 @@ TODO
### Add the test ingress
```bash
kubectl apply -f https://github.com/kubernetes/minikube/blob/master/deploy/addons/ingress-dns/example/example.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/minikube/master/deploy/addons/ingress-dns/example/example.yaml
```
Note: Minimum Kubernetes version for example ingress is 1.14.7

View File

@ -8,7 +8,7 @@ metadata:
kubernetes.io/minikube-addons: storage-provisioner-gluster
addonmanager.kubernetes.io/mode: EnsureExists
annotations:
storageclass.beta.kubernetes.io/is-default-class: "true"
storageclass.kubernetes.io/is-default-class: "true"
provisioner: gluster.org/glusterfile
reclaimPolicy: Delete
parameters:

View File

@ -4,6 +4,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
@ -29,29 +30,11 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_BPF_SYSCALL=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_OSF_PARTITION=y
CONFIG_AMIGA_PARTITION=y
CONFIG_MAC_PARTITION=y
CONFIG_BSD_DISKLABEL=y
CONFIG_MINIX_SUBPARTITION=y
CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SGI_PARTITION=y
CONFIG_SUN_PARTITION=y
CONFIG_KARMA_PARTITION=y
CONFIG_SMP=y
CONFIG_HYPERVISOR_GUEST=y
CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_KVM_DEBUG_FS=y
CONFIG_CALGARY_IOMMU=y
CONFIG_SCHED_SMT=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
CONFIG_MICROCODE_AMD=y
CONFIG_X86_MSR=y
@ -71,13 +54,34 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_X86_ACPI_CPUFREQ=y
CONFIG_PCI_MMCONFIG=y
CONFIG_PCIEPORTBUS=y
CONFIG_HOTPLUG_PCI=y
CONFIG_PCCARD=y
CONFIG_YENTA=y
CONFIG_BINFMT_MISC=y
CONFIG_IA32_EMULATION=y
CONFIG_EFI_VARS=y
CONFIG_KVM=m
CONFIG_KVM_INTEL=m
CONFIG_KVM_AMD=m
CONFIG_VHOST_NET=m
CONFIG_VHOST_VSOCK=m
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_OSF_PARTITION=y
CONFIG_AMIGA_PARTITION=y
CONFIG_MAC_PARTITION=y
CONFIG_BSD_DISKLABEL=y
CONFIG_MINIX_SUBPARTITION=y
CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_SGI_PARTITION=y
CONFIG_SUN_PARTITION=y
CONFIG_KARMA_PARTITION=y
CONFIG_BINFMT_MISC=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@ -226,8 +230,6 @@ CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
CONFIG_IP_VS_NFCT=y
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_NF_SOCKET_IPV4=m
CONFIG_NF_LOG_ARP=m
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_FILTER=y
@ -238,8 +240,6 @@ CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_MANGLE=y
CONFIG_IP_NF_RAW=m
CONFIG_NF_CONNTRACK_IPV6=m
CONFIG_NF_SOCKET_IPV6=m
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MATCH_IPV6HEADER=y
CONFIG_IP6_NF_FILTER=y
@ -268,14 +268,15 @@ CONFIG_BRIDGE_EBT_LOG=m
CONFIG_BRIDGE_EBT_NFLOG=m
CONFIG_BRIDGE=m
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_NETEM=y
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_NET_CLS_BPF=m
CONFIG_NET_EMATCH=y
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_BPF=m
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_ACT_BPF=m
CONFIG_OPENVSWITCH=m
CONFIG_VSOCKETS=m
CONFIG_VIRTIO_VSOCKETS=m
@ -322,6 +323,7 @@ CONFIG_PATA_SCH=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_DM_SNAPSHOT=y
CONFIG_DM_THIN_PROVISIONING=y
CONFIG_DM_MIRROR=y
@ -342,7 +344,6 @@ CONFIG_IPVLAN=m
CONFIG_VXLAN=y
CONFIG_NETCONSOLE=y
CONFIG_TUN=y
CONFIG_TAP=y
CONFIG_VETH=y
CONFIG_VIRTIO_NET=y
CONFIG_AMD8111_ETH=m
@ -439,7 +440,6 @@ CONFIG_EEEPC_LAPTOP=y
CONFIG_AMD_IOMMU=y
CONFIG_INTEL_IOMMU=y
# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
CONFIG_EFI_VARS=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
@ -480,8 +480,16 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_DISABLE=y
CONFIG_CRYPTO_XTS=y
CONFIG_CRYPTO_AES_NI_INTEL=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_USER_API_SKCIPHER=y
CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
@ -494,15 +502,3 @@ CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
CONFIG_EARLY_PRINTK_DBGP=y
CONFIG_DEBUG_BOOT_PARAMS=y
CONFIG_OPTIMIZE_INLINING=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_DISABLE=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_KVM=m
CONFIG_KVM_INTEL=m
CONFIG_KVM_AMD=m
CONFIG_VHOST_NET=m
CONFIG_VHOST=m
CONFIG_VHOST_VSOCK=m

View File

@ -60,3 +60,6 @@ BR2_TARGET_ROOTFS_ISO9660_BOOT_MENU="$(BR2_EXTERNAL_MINIKUBE_PATH)/board/coreos/
BR2_TARGET_SYSLINUX=y
BR2_PACKAGE_HOST_E2TOOLS=y
BR2_PACKAGE_SYSTEMD_TIMESYNCD=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_SYSSTAT=y
BR2_PACKAGE_HTOP=y

View File

@ -1,4 +1,20 @@
[
{
"name": "v1.6.1",
"checksums": {
"darwin": "bcfc181ade08bd2a87fca70f0aa59f9f4b23c893fc2b335b3cb8f05b84ae2d34",
"linux": "cbd526d64531266d42f02667339d3c53e5a399e3abebda63c96b0bbd6b7e935d",
"windows": "1d7372fcf099d583d4140a4ce4aa8f5c2752d3bd0d143e53647aee6221dcb663"
}
},
{
"name": "v1.6.0",
"checksums": {
"darwin": "fd1af02f0fc11fb0bec35b9ae1f6bf2d157f51948155d8b1ddc899521642fc32",
"linux": "48738607ecdb0b00815599230a2a2b17dc90bd3bbcb1b217bace043f78370db3",
"windows": "20e7db220308f06913acd10addb1ec01c87b74245cebc70fa18a979c1b323f34"
}
},
{
"name": "v1.5.2",
"checksums": {

View File

@ -258,6 +258,7 @@ if [[ "${LOAD}" -gt 2 ]]; then
uptime
fi
e2e_start_time="$(date -u +%s)"
echo ""
echo ">> Starting ${E2E_BIN} at $(date)"
set -x
@ -279,9 +280,19 @@ else
echo "minikube: FAIL"
fi
## caclucate the time took to finish running e2e binary test.
e2e_end_time="$(date -u +%s)"
elapsed=$(($e2e_end_time-$e2e_start_time))
min=$(($elapsed/60))
sec=$(tail -c 3 <<< $((${elapsed}00/60)))
elapsed=$min.$sec
description="completed with ${status} in ${elapsed} minute(s)."
echo $description
echo ">> Cleaning up after ourselves ..."
${SUDO_PREFIX}${MINIKUBE_BIN} tunnel --cleanup || true
${SUDO_PREFIX}${MINIKUBE_BIN} delete >/dev/null 2>/dev/null || true
${SUDO_PREFIX}${MINIKUBE_BIN} delete --all >/dev/null 2>/dev/null || true
cleanup_stale_routes || true
${SUDO_PREFIX} rm -Rf "${MINIKUBE_HOME}" || true
@ -300,6 +311,7 @@ function retry_github_status() {
local state=$3
local token=$4
local target=$5
local desc=$6
# Retry in case we hit our GitHub API quota or fail other ways.
local attempt=0
@ -312,7 +324,7 @@ function retry_github_status() {
"https://api.github.com/repos/kubernetes/minikube/statuses/${commit}?access_token=${token}" \
-H "Content-Type: application/json" \
-X POST \
-d "{\"state\": \"${state}\", \"description\": \"Jenkins\", \"target_url\": \"${target}\", \"context\": \"${context}\"}" || echo 999)
-d "{\"state\": \"${state}\", \"description\": \"Jenkins: ${desc}\", \"target_url\": \"${target}\", \"context\": \"${context}\"}" || echo 999)
# 2xx HTTP codes
if [[ "${code}" =~ ^2 ]]; then
@ -327,5 +339,7 @@ function retry_github_status() {
done
}
retry_github_status "${COMMIT}" "${JOB_NAME}" "${status}" "${access_token}" "https://storage.googleapis.com/minikube-builds/logs/${MINIKUBE_LOCATION}/${JOB_NAME}.txt"
retry_github_status "${COMMIT}" "${JOB_NAME}" "${status}" "${access_token}" "https://storage.googleapis.com/minikube-builds/logs/${MINIKUBE_LOCATION}/${JOB_NAME}.txt" "${description}"
exit $result

View File

@ -34,7 +34,10 @@ if ! [[ -x "${DIR}/release-notes" ]]; then
install_release_notes_helper
fi
"${DIR}/release-notes" kubernetes minikube
git pull git@github.com:kubernetes/minikube master --tags
recent=$(git describe --abbrev=0)
"${DIR}/release-notes" kubernetes minikube --since $recent
echo "Huge thank you for this release towards our contributors: "
git log "$(git describe --abbrev=0)".. --format="%aN" --reverse | sort | uniq | awk '{printf "- %s\n", $0 }'
git log "$recent".. --format="%aN" --reverse | sort | uniq | awk '{printf "- %s\n", $0 }'

View File

@ -39,7 +39,7 @@ const (
containerdConfigTomlPath = "/etc/containerd/config.toml"
storedContainerdConfigTomlPath = "/tmp/config.toml"
gvisorContainerdShimURL = "https://github.com/google/gvisor-containerd-shim/releases/download/v0.0.3/containerd-shim-runsc-v1.linux-amd64"
gvisorURL = "https://storage.googleapis.com/gvisor/releases/nightly/2019-01-14/runsc"
gvisorURL = "https://storage.googleapis.com/gvisor/releases/nightly/2019-11-27/runsc"
)
// Enable follows these steps for enabling gvisor in minikube:

View File

@ -38,7 +38,7 @@ type Bootstrapper interface {
// PullImages pulls images necessary for a cluster. Success should not be required.
PullImages(config.KubernetesConfig) error
StartCluster(config.KubernetesConfig) error
UpdateCluster(config.KubernetesConfig) error
UpdateCluster(config.MachineConfig) error
DeleteCluster(config.KubernetesConfig) error
WaitForCluster(config.KubernetesConfig, time.Duration) error
// LogCommands returns a map of log type to a command which will display that log.
@ -64,12 +64,11 @@ func GetCachedBinaryList(bootstrapper string) []string {
}
// GetCachedImageList returns the list of images for a version
func GetCachedImageList(imageRepository string, version string, bootstrapper string) []string {
func GetCachedImageList(imageRepository string, version string, bootstrapper string) ([]string, error) {
switch bootstrapper {
case BootstrapperTypeKubeadm:
images := images.CachedImages(imageRepository, version)
return images
return images.Kubeadm(imageRepository, version)
default:
return []string{}
return []string{}, nil
}
}

View File

@ -26,7 +26,6 @@ import (
"path"
"path/filepath"
"strings"
"time"
"github.com/golang/glog"
"github.com/pkg/errors"
@ -40,8 +39,8 @@ import (
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/vmpath"
"k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/lock"
"github.com/juju/clock"
"github.com/juju/mutex"
)
@ -61,17 +60,17 @@ var (
// SetupCerts gets the generated credentials required to talk to the APIServer.
func SetupCerts(cmd command.Runner, k8s config.KubernetesConfig) error {
localPath := localpath.MiniPath()
glog.Infof("Setting up %s for IP: %s\n", localPath, k8s.NodeIP)
// WARNING: This function was not designed for multiple profiles, so it is VERY racey:
//
// It updates a shared certificate file and uploads it to the apiserver before launch.
//
// If another process updates the shared certificate, it's invalid.
// TODO: Instead of racey manipulation of a shared certificate, use per-profile certs
spec := mutex.Spec{
Name: "setupCerts",
Clock: clock.WallClock,
Delay: 15 * time.Second,
}
spec := lock.PathMutexSpec(filepath.Join(localPath, "certs"))
glog.Infof("acquiring lock: %+v", spec)
releaser, err := mutex.Acquire(spec)
if err != nil {
@ -79,9 +78,6 @@ func SetupCerts(cmd command.Runner, k8s config.KubernetesConfig) error {
}
defer releaser.Release()
localPath := localpath.MiniPath()
glog.Infof("Setting up %s for IP: %s\n", localPath, k8s.NodeIP)
if err := generateCerts(k8s); err != nil {
return errors.Wrap(err, "Error generating certs")
}

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");
you may not use this file except in compliance with the License.
@ -14,186 +14,63 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package images implements helpers for getting image names
package images
import (
"path"
"runtime"
"strings"
"github.com/blang/semver"
"github.com/golang/glog"
minikubeVersion "k8s.io/minikube/pkg/version"
)
const (
// DefaultImageRepo is the default repository for images
DefaultImageRepo = "k8s.gcr.io"
// DefaultMinikubeRepo is the default repository for minikube
DefaultMinikubeRepo = "gcr.io/k8s-minikube"
)
// getImageRepositories returns either the k8s image registry on GCR or a mirror if specified
func getImageRepository(imageRepository string) string {
if imageRepository == "" {
imageRepository = DefaultImageRepo
}
if !strings.HasSuffix(imageRepository, "/") {
imageRepository += "/"
}
return imageRepository
}
// getMinikubeRepository returns either the minikube image registry on GCR or a mirror if specified
func getMinikubeRepository(imageRepository string) string {
minikubeRepository := imageRepository
if minikubeRepository == "" {
minikubeRepository = DefaultMinikubeRepo
}
if !strings.HasSuffix(minikubeRepository, "/") {
minikubeRepository += "/"
}
return minikubeRepository
}
// CachedImages gets the images to cache for kubeadm for a version
func CachedImages(imageRepositoryStr string, kubernetesVersionStr string) []string {
imageRepository := getImageRepository(imageRepositoryStr)
minikubeRepository := getMinikubeRepository(imageRepositoryStr)
v1_16plus := semver.MustParseRange(">=1.16.0")
v1_14plus := semver.MustParseRange(">=1.14.0 <1.16.0")
v1_13 := semver.MustParseRange(">=1.13.0 <1.14.0")
v1_12 := semver.MustParseRange(">=1.12.0 <1.13.0")
v1_11 := semver.MustParseRange(">=1.11.0 <1.12.0")
v1_12plus := semver.MustParseRange(">=1.12.0")
kubernetesVersion, err := semver.Make(strings.TrimPrefix(kubernetesVersionStr, minikubeVersion.VersionPrefix))
if err != nil {
glog.Errorln("Error parsing version semver: ", err)
}
var images []string
if v1_12plus(kubernetesVersion) {
images = append(images, []string{
imageRepository + "kube-proxy" + ArchTag(false) + kubernetesVersionStr,
imageRepository + "kube-scheduler" + ArchTag(false) + kubernetesVersionStr,
imageRepository + "kube-controller-manager" + ArchTag(false) + kubernetesVersionStr,
imageRepository + "kube-apiserver" + ArchTag(false) + kubernetesVersionStr,
}...)
} else {
images = append(images, []string{
imageRepository + "kube-proxy" + ArchTag(true) + kubernetesVersionStr,
imageRepository + "kube-scheduler" + ArchTag(true) + kubernetesVersionStr,
imageRepository + "kube-controller-manager" + ArchTag(true) + kubernetesVersionStr,
imageRepository + "kube-apiserver" + ArchTag(true) + kubernetesVersionStr,
}...)
}
podInfraContainerImage := PauseImage(imageRepository, kubernetesVersionStr)
if v1_16plus(kubernetesVersion) {
images = append(images, []string{
podInfraContainerImage,
imageRepository + "k8s-dns-kube-dns" + ArchTag(true) + "1.14.13",
imageRepository + "k8s-dns-dnsmasq-nanny" + ArchTag(true) + "1.14.13",
imageRepository + "k8s-dns-sidecar" + ArchTag(true) + "1.14.13",
imageRepository + "etcd" + ArchTag(false) + "3.3.15-0",
imageRepository + "coredns" + ArchTag(false) + "1.6.2",
}...)
} else if v1_14plus(kubernetesVersion) {
images = append(images, []string{
podInfraContainerImage,
imageRepository + "k8s-dns-kube-dns" + ArchTag(true) + "1.14.13",
imageRepository + "k8s-dns-dnsmasq-nanny" + ArchTag(true) + "1.14.13",
imageRepository + "k8s-dns-sidecar" + ArchTag(true) + "1.14.13",
imageRepository + "etcd" + ArchTag(false) + "3.3.10",
imageRepository + "coredns" + ArchTag(false) + "1.3.1",
}...)
} else if v1_13(kubernetesVersion) {
images = append(images, []string{
podInfraContainerImage,
imageRepository + "k8s-dns-kube-dns" + ArchTag(true) + "1.14.8",
imageRepository + "k8s-dns-dnsmasq-nanny" + ArchTag(true) + "1.14.8",
imageRepository + "k8s-dns-sidecar" + ArchTag(true) + "1.14.8",
imageRepository + "etcd" + ArchTag(false) + "3.2.24",
imageRepository + "coredns:1.2.6",
}...)
} else if v1_12(kubernetesVersion) {
images = append(images, []string{
podInfraContainerImage,
imageRepository + "k8s-dns-kube-dns" + ArchTag(true) + "1.14.8",
imageRepository + "k8s-dns-dnsmasq-nanny" + ArchTag(true) + "1.14.8",
imageRepository + "k8s-dns-sidecar" + ArchTag(true) + "1.14.8",
imageRepository + "etcd" + ArchTag(false) + "3.2.24",
imageRepository + "coredns:1.2.2",
}...)
} else if v1_11(kubernetesVersion) {
images = append(images, []string{
podInfraContainerImage,
imageRepository + "k8s-dns-kube-dns" + ArchTag(true) + "1.14.8",
imageRepository + "k8s-dns-dnsmasq-nanny" + ArchTag(true) + "1.14.8",
imageRepository + "k8s-dns-sidecar" + ArchTag(true) + "1.14.8",
imageRepository + "etcd" + ArchTag(true) + "3.2.18",
imageRepository + "coredns:1.1.3",
}...)
}
images = append(images, []string{
imageRepository + "kube-addon-manager" + ArchTag(false) + "v9.0",
minikubeRepository + "storage-provisioner" + ArchTag(false) + "v1.8.1",
}...)
return images
}
// PauseImage returns the image name for pause image (for pod infra)
func PauseImage(imageRepositoryStr string, kubernetesVersionStr string) string {
imageRepository := getImageRepository(imageRepositoryStr)
v1_16plus := semver.MustParseRange(">=1.16.0")
v1_14plus := semver.MustParseRange(">=1.14.0 <1.16.0")
v1_13 := semver.MustParseRange(">=1.13.0 <1.14.0")
v1_12 := semver.MustParseRange(">=1.12.0 <1.13.0")
v1_11 := semver.MustParseRange(">=1.11.0 <1.12.0")
kubernetesVersion, err := semver.Make(strings.TrimPrefix(kubernetesVersionStr, minikubeVersion.VersionPrefix))
if err != nil {
glog.Errorln("Error parsing version semver: ", err)
}
var podInfraContainerImage string
switch {
case v1_16plus(kubernetesVersion):
podInfraContainerImage = imageRepository + "pause:3.1"
case v1_14plus(kubernetesVersion):
podInfraContainerImage = imageRepository + "pause:3.1"
case v1_13(kubernetesVersion):
podInfraContainerImage = imageRepository + "pause" + ArchTag(false) + "3.1"
case v1_12(kubernetesVersion):
podInfraContainerImage = imageRepository + "pause:3.1"
case v1_11(kubernetesVersion):
podInfraContainerImage = imageRepository + "pause" + ArchTag(false) + "3.1"
default:
podInfraContainerImage = imageRepository + "pause" + ArchTag(false) + "3.0"
}
return podInfraContainerImage
}
// ArchTag returns the archtag for images
// ArchTag returns a CPU architecture suffix for images
func ArchTag(hasTag bool) string {
if runtime.GOARCH == "amd64" && !hasTag {
return ":"
}
return "-" + runtime.GOARCH + ":"
}
// Auxiliary returns images that are helpful for running minikube
func Auxiliary(mirror string) []string {
return []string{
addonManager(mirror),
storageProvisioner(mirror),
dashboardFrontend(mirror),
dashboardMetrics(mirror),
}
}
// Pause returns the image name to pull for the pause image
func Pause(mirror string) string {
// Should match `PauseVersion` in:
// https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants.go
return path.Join(KubernetesRepo(mirror), "pause"+ArchTag(false)+"3.1")
}
// storageProvisioner returns the minikube storage provisioner image
func storageProvisioner(mirror string) string {
return path.Join(minikubeRepo(mirror), "storage-provisioner"+ArchTag(false)+"v1.8.1")
}
// addonManager returns the Kubernetes addon manager image
func addonManager(mirror string) string {
return path.Join(KubernetesRepo(mirror), "kube-addon-manager"+ArchTag(false)+"v9.0.2")
}
// dashboardFrontend returns the image used for the dashboard frontend
func dashboardFrontend(repo string) string {
if repo == "" {
repo = "kubernetesui"
}
// See 'kubernetes-dashboard' in deploy/addons/dashboard/dashboard-dp.yaml
return path.Join(repo, "dashboard:v2.0.0-beta8")
}
// dashboardMetrics returns the image used for the dashboard metrics scraper
func dashboardMetrics(repo string) string {
if repo == "" {
repo = "kubernetesui"
}
// See 'dashboard-metrics-scraper' in deploy/addons/dashboard/dashboard-dp.yaml
return path.Join(repo, "metrics-scraper:v1.0.2")
}

View File

@ -0,0 +1,49 @@
/*
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 images
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestAuxiliary(t *testing.T) {
want := []string{
"k8s.gcr.io/kube-addon-manager:v9.0.2",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-beta8",
"kubernetesui/metrics-scraper:v1.0.2",
}
got := Auxiliary("")
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("images mismatch (-want +got):\n%s", diff)
}
}
func TestAuxiliaryMirror(t *testing.T) {
want := []string{
"test.mirror/kube-addon-manager:v9.0.2",
"test.mirror/storage-provisioner:v1.8.1",
"test.mirror/dashboard:v2.0.0-beta8",
"test.mirror/metrics-scraper:v1.0.2",
}
got := Auxiliary("test.mirror")
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("images mismatch (-want +got):\n%s", diff)
}
}

View File

@ -0,0 +1,101 @@
/*
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 images
import (
"fmt"
"path"
"strings"
"github.com/blang/semver"
"github.com/pkg/errors"
)
// Kubeadm returns a list of images necessary to bootstrap kubeadm
func Kubeadm(mirror string, version string) ([]string, error) {
v, err := semver.Make(strings.TrimPrefix(version, "v"))
if err != nil {
return nil, errors.Wrap(err, "semver")
}
imgs := []string{
componentImage("kube-proxy", v, mirror),
componentImage("kube-scheduler", v, mirror),
componentImage("kube-controller-manager", v, mirror),
componentImage("kube-apiserver", v, mirror),
coreDNS(v, mirror),
etcd(v, mirror),
Pause(mirror),
}
imgs = append(imgs, Auxiliary(mirror)...)
return imgs, nil
}
// componentImage returns a Kubernetes component image to pull
func componentImage(name string, v semver.Version, mirror string) string {
needsArchSuffix := false
ancient := semver.MustParseRange("<1.12.0")
if ancient(v) {
needsArchSuffix = true
}
return fmt.Sprintf("%sv%s", path.Join(KubernetesRepo(mirror), name+ArchTag(needsArchSuffix)), v)
}
// coreDNS returns the images used for CoreDNS
func coreDNS(v semver.Version, mirror string) string {
// Should match `CoreDNSVersion` in
// https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants.go
cv := "1.6.5"
switch v.Minor {
case 16:
cv = "1.6.2"
case 15, 14:
cv = "1.3.1"
case 13:
cv = "1.2.6"
case 12:
cv = "1.2.2"
case 11:
cv = "1.1.3"
}
return path.Join(KubernetesRepo(mirror), "coredns"+ArchTag(false)+cv)
}
// etcd returns the image used for etcd
func etcd(v semver.Version, mirror string) string {
needsArchSuffix := false
ancient := semver.MustParseRange("<1.12.0")
if ancient(v) {
needsArchSuffix = true
}
// Should match `DefaultEtcdVersion` in:
// https://github.com/kubernetes/kubernetes/blob/master/cmd/kubeadm/app/constants/constants.go
ev := "3.4.3-0"
switch v.Minor {
case 16:
ev = "3.3.15-0"
case 14, 15:
ev = "3.3.10"
case 12, 13:
ev = "3.2.24"
case 11:
ev = "3.2.18"
}
return path.Join(KubernetesRepo(mirror), "etcd"+ArchTag(needsArchSuffix)+ev)
}

View File

@ -0,0 +1,135 @@
/*
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 images
import (
"sort"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestKubeadmImages(t *testing.T) {
tests := []struct {
version string
mirror string
want []string
}{
{"v1.17.0", "", []string{
"k8s.gcr.io/kube-proxy:v1.17.0",
"k8s.gcr.io/kube-scheduler:v1.17.0",
"k8s.gcr.io/kube-controller-manager:v1.17.0",
"k8s.gcr.io/kube-apiserver:v1.17.0",
"k8s.gcr.io/coredns:1.6.5",
"k8s.gcr.io/etcd:3.4.3-0",
"k8s.gcr.io/pause:3.1",
"k8s.gcr.io/kube-addon-manager:v9.0.2",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-beta8",
"kubernetesui/metrics-scraper:v1.0.2",
}},
{"v1.16.1", "mirror.k8s.io", []string{
"mirror.k8s.io/kube-proxy:v1.16.1",
"mirror.k8s.io/kube-scheduler:v1.16.1",
"mirror.k8s.io/kube-controller-manager:v1.16.1",
"mirror.k8s.io/kube-apiserver:v1.16.1",
"mirror.k8s.io/coredns:1.6.2",
"mirror.k8s.io/etcd:3.3.15-0",
"mirror.k8s.io/pause:3.1",
"mirror.k8s.io/kube-addon-manager:v9.0.2",
"mirror.k8s.io/storage-provisioner:v1.8.1",
"mirror.k8s.io/dashboard:v2.0.0-beta8",
"mirror.k8s.io/metrics-scraper:v1.0.2",
}},
{"v1.15.0", "", []string{
"k8s.gcr.io/kube-proxy:v1.15.0",
"k8s.gcr.io/kube-scheduler:v1.15.0",
"k8s.gcr.io/kube-controller-manager:v1.15.0",
"k8s.gcr.io/kube-apiserver:v1.15.0",
"k8s.gcr.io/coredns:1.3.1",
"k8s.gcr.io/etcd:3.3.10",
"k8s.gcr.io/pause:3.1",
"k8s.gcr.io/kube-addon-manager:v9.0.2",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-beta8",
"kubernetesui/metrics-scraper:v1.0.2",
}},
{"v1.14.0", "", []string{
"k8s.gcr.io/kube-proxy:v1.14.0",
"k8s.gcr.io/kube-scheduler:v1.14.0",
"k8s.gcr.io/kube-controller-manager:v1.14.0",
"k8s.gcr.io/kube-apiserver:v1.14.0",
"k8s.gcr.io/coredns:1.3.1",
"k8s.gcr.io/etcd:3.3.10",
"k8s.gcr.io/pause:3.1",
"k8s.gcr.io/kube-addon-manager:v9.0.2",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-beta8",
"kubernetesui/metrics-scraper:v1.0.2",
}},
{"v1.13.0", "", []string{
"k8s.gcr.io/kube-proxy:v1.13.0",
"k8s.gcr.io/kube-scheduler:v1.13.0",
"k8s.gcr.io/kube-controller-manager:v1.13.0",
"k8s.gcr.io/kube-apiserver:v1.13.0",
"k8s.gcr.io/coredns:1.2.6",
"k8s.gcr.io/etcd:3.2.24",
"k8s.gcr.io/pause:3.1",
"k8s.gcr.io/kube-addon-manager:v9.0.2",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-beta8",
"kubernetesui/metrics-scraper:v1.0.2",
}},
{"v1.12.0", "", []string{
"k8s.gcr.io/kube-proxy:v1.12.0",
"k8s.gcr.io/kube-scheduler:v1.12.0",
"k8s.gcr.io/kube-controller-manager:v1.12.0",
"k8s.gcr.io/kube-apiserver:v1.12.0",
"k8s.gcr.io/coredns:1.2.2",
"k8s.gcr.io/etcd:3.2.24",
"k8s.gcr.io/pause:3.1",
"k8s.gcr.io/kube-addon-manager:v9.0.2",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-beta8",
"kubernetesui/metrics-scraper:v1.0.2",
}},
{"v1.11.10", "", []string{
"k8s.gcr.io/kube-proxy-amd64:v1.11.10",
"k8s.gcr.io/kube-scheduler-amd64:v1.11.10",
"k8s.gcr.io/kube-controller-manager-amd64:v1.11.10",
"k8s.gcr.io/kube-apiserver-amd64:v1.11.10",
"k8s.gcr.io/coredns:1.1.3",
"k8s.gcr.io/etcd-amd64:3.2.18",
"k8s.gcr.io/pause:3.1",
"k8s.gcr.io/kube-addon-manager:v9.0.2",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-beta8",
"kubernetesui/metrics-scraper:v1.0.2",
}},
}
for _, tc := range tests {
got, err := Kubeadm(tc.mirror, tc.version)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
sort.Strings(got)
sort.Strings(tc.want)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("%s images mismatch (-want +got):\n%s", tc.version, diff)
}
}
}

View File

@ -0,0 +1,36 @@
/*
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 images
// DefaultKubernetesRepo is the default Kubernetes repository
const DefaultKubernetesRepo = "k8s.gcr.io"
// KubernetesRepo returns the official Kubernetes repository, or an alternate
func KubernetesRepo(mirror string) string {
if mirror != "" {
return mirror
}
return DefaultKubernetesRepo
}
// minikubeRepo returns the official minikube repository, or an alternate
func minikubeRepo(mirror string) string {
if mirror != "" {
return mirror
}
return "gcr.io/k8s-minikube"
}

View File

@ -596,7 +596,7 @@ func NewKubeletConfig(k8s config.KubernetesConfig, r cruntime.Manager) ([]byte,
extraOpts["node-ip"] = k8s.NodeIP
}
pauseImage := images.PauseImage(k8s.ImageRepository, k8s.KubernetesVersion)
pauseImage := images.Pause(k8s.ImageRepository)
if _, ok := extraOpts["pod-infra-container-image"]; !ok && k8s.ImageRepository != "" && pauseImage != "" && k8s.ContainerRuntime != remoteContainerRuntime {
extraOpts["pod-infra-container-image"] = pauseImage
}
@ -629,33 +629,37 @@ func NewKubeletConfig(k8s config.KubernetesConfig, r cruntime.Manager) ([]byte,
}
// UpdateCluster updates the cluster
func (k *Bootstrapper) UpdateCluster(cfg config.KubernetesConfig) error {
images := images.CachedImages(cfg.ImageRepository, cfg.KubernetesVersion)
if cfg.ShouldLoadCachedImages {
if err := machine.LoadImages(k.c, images, constants.ImageCacheDir); err != nil {
func (k *Bootstrapper) UpdateCluster(cfg config.MachineConfig) error {
images, err := images.Kubeadm(cfg.KubernetesConfig.ImageRepository, cfg.KubernetesConfig.KubernetesVersion)
if err != nil {
return errors.Wrap(err, "kubeadm images")
}
if cfg.KubernetesConfig.ShouldLoadCachedImages {
if err := machine.LoadImages(&cfg, k.c, images, constants.ImageCacheDir); err != nil {
out.FailureT("Unable to load cached images: {{.error}}", out.V{"error": err})
}
}
r, err := cruntime.New(cruntime.Config{Type: cfg.ContainerRuntime, Socket: cfg.CRISocket})
r, err := cruntime.New(cruntime.Config{Type: cfg.ContainerRuntime, Socket: cfg.KubernetesConfig.CRISocket})
if err != nil {
return errors.Wrap(err, "runtime")
}
kubeadmCfg, err := generateConfig(cfg, r)
kubeadmCfg, err := generateConfig(cfg.KubernetesConfig, r)
if err != nil {
return errors.Wrap(err, "generating kubeadm cfg")
}
kubeletCfg, err := NewKubeletConfig(cfg, r)
kubeletCfg, err := NewKubeletConfig(cfg.KubernetesConfig, r)
if err != nil {
return errors.Wrap(err, "generating kubelet config")
}
kubeletService, err := NewKubeletService(cfg)
kubeletService, err := NewKubeletService(cfg.KubernetesConfig)
if err != nil {
return errors.Wrap(err, "generating kubelet service")
}
glog.Infof("kubelet %s config:\n%s", cfg.KubernetesVersion, kubeletCfg)
glog.Infof("kubelet %s config:\n%+v", kubeletCfg, cfg.KubernetesConfig)
stopCmd := exec.Command("/bin/bash", "-c", "pgrep kubelet && sudo systemctl stop kubelet")
// stop kubelet to avoid "Text File Busy" error
@ -663,11 +667,11 @@ func (k *Bootstrapper) UpdateCluster(cfg config.KubernetesConfig) error {
glog.Warningf("unable to stop kubelet: %s command: %q output: %q", err, rr.Command(), rr.Output())
}
if err := transferBinaries(cfg, k.c); err != nil {
if err := transferBinaries(cfg.KubernetesConfig, k.c); err != nil {
return errors.Wrap(err, "downloading binaries")
}
files := configFiles(cfg, kubeadmCfg, kubeletCfg, kubeletService)
if err := addAddons(&files, assets.GenerateTemplateData(cfg)); err != nil {
files := configFiles(cfg.KubernetesConfig, kubeadmCfg, kubeletCfg, kubeletService)
if err := addAddons(&files, assets.GenerateTemplateData(cfg.KubernetesConfig)); err != nil {
return errors.Wrap(err, "adding addons")
}
for _, f := range files {

View File

@ -66,7 +66,7 @@ Wants=crio.service
[Service]
ExecStart=
ExecStart=/var/lib/minikube/binaries/v1.17.0-rc.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 --config=/var/lib/kubelet/config.yaml --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.17.0/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 --config=/var/lib/kubelet/config.yaml --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.17.0-rc.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 --config=/var/lib/kubelet/config.yaml --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.17.0/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 --config=/var/lib/kubelet/config.yaml --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.17.0-rc.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 --config=/var/lib/kubelet/config.yaml --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.17.0/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 --config=/var/lib/kubelet/config.yaml --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.17.0-rc.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 --config=/var/lib/kubelet/config.yaml --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.17.0/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 --config=/var/lib/kubelet/config.yaml --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

@ -24,7 +24,6 @@ import (
"io/ioutil"
"os"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/minikube/localpath"
)
@ -124,9 +123,8 @@ func encode(w io.Writer, m MinikubeConfig) error {
}
// Load loads the kubernetes and machine config for the current machine
func Load() (*MachineConfig, error) {
machine := viper.GetString(MachineProfile)
return DefaultLoader.LoadConfigFromFile(machine)
func Load(profile string) (*MachineConfig, error) {
return DefaultLoader.LoadConfigFromFile(profile)
}
// Loader loads the kubernetes and machine config based on the machine profile name

View File

@ -105,7 +105,7 @@ func CreateProfile(name string, cfg *MachineConfig, miniHome ...string) error {
}
defer os.Remove(tf.Name())
if err = lock.WriteFile(tf.Name(), data, 0600); err != nil {
if err = ioutil.WriteFile(tf.Name(), data, 0600); err != nil {
return err
}

View File

@ -26,6 +26,7 @@ import (
// Profile represents a minikube profile
type Profile struct {
Name string
Status string // running, stopped
Config []*MachineConfig
}

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.17.0-rc.1"
var DefaultKubernetesVersion = "v1.17.0"
// NewestKubernetesVersion is the newest Kubernetes version to test against
var NewestKubernetesVersion = "v1.17.0-rc.1"
var NewestKubernetesVersion = "v1.17.0"
// OldestKubernetesVersion is the oldest Kubernetes version to test against
var OldestKubernetesVersion = "v1.11.10"

View File

@ -169,13 +169,13 @@ func (r *Containerd) Available() error {
}
// generateContainerdConfig sets up /etc/containerd/config.toml
func generateContainerdConfig(cr CommandRunner, imageRepository string, k8sVersion string) error {
func generateContainerdConfig(cr CommandRunner, imageRepository string) error {
cPath := containerdConfigFile
t, err := template.New("containerd.config.toml").Parse(containerdConfigTemplate)
if err != nil {
return err
}
pauseImage := images.PauseImage(imageRepository, k8sVersion)
pauseImage := images.Pause(imageRepository)
opts := struct{ PodInfraContainerImage string }{PodInfraContainerImage: pauseImage}
var b bytes.Buffer
if err := t.Execute(&b, opts); err != nil {
@ -198,7 +198,7 @@ func (r *Containerd) Enable(disOthers bool) error {
if err := populateCRIConfig(r.Runner, r.SocketPath()); err != nil {
return err
}
if err := generateContainerdConfig(r.Runner, r.ImageRepository, r.KubernetesVersion); err != nil {
if err := generateContainerdConfig(r.Runner, r.ImageRepository); err != nil {
return err
}
if err := enableIPForwarding(r.Runner); err != nil {
@ -221,6 +221,15 @@ func (r *Containerd) Disable() error {
return nil
}
// ImageExists checks if an image exists, expected input format
func (r *Containerd) ImageExists(name string, sha string) bool {
c := exec.Command("/bin/bash", "-c", fmt.Sprintf("sudo ctr -n=k8s.io images check | grep %s | grep %s", name, sha))
if _, err := r.Runner.RunCmd(c); err != nil {
return false
}
return true
}
// LoadImage loads an image into this runtime
func (r *Containerd) LoadImage(path string) error {
glog.Infof("Loading image: %s", path)

View File

@ -407,13 +407,13 @@ image-endpoint: unix://{{.Socket}}
}
// generateCRIOConfig sets up /etc/crio/crio.conf
func generateCRIOConfig(cr CommandRunner, imageRepository string, k8sVersion string) error {
func generateCRIOConfig(cr CommandRunner, imageRepository string) error {
cPath := crioConfigFile
t, err := template.New("crio.conf").Parse(crioConfigTemplate)
if err != nil {
return err
}
pauseImage := images.PauseImage(imageRepository, k8sVersion)
pauseImage := images.Pause(imageRepository)
opts := struct{ PodInfraContainerImage string }{PodInfraContainerImage: pauseImage}
var b bytes.Buffer
if err := t.Execute(&b, opts); err != nil {

View File

@ -98,7 +98,7 @@ func (r *CRIO) Enable(disOthers bool) error {
if err := populateCRIConfig(r.Runner, r.SocketPath()); err != nil {
return err
}
if err := generateCRIOConfig(r.Runner, r.ImageRepository, r.KubernetesVersion); err != nil {
if err := generateCRIOConfig(r.Runner, r.ImageRepository); err != nil {
return err
}
if err := enableIPForwarding(r.Runner); err != nil {
@ -119,6 +119,20 @@ func (r *CRIO) Disable() error {
return nil
}
// ImageExists checks if an image exists
func (r *CRIO) ImageExists(name string, sha string) bool {
// expected output looks like [NAME@sha256:SHA]
c := exec.Command("sudo", "podman", "inspect", "--format='{{.Id}}'", name)
rr, err := r.Runner.RunCmd(c)
if err != nil {
return false
}
if !strings.Contains(rr.Output(), sha) {
return false
}
return true
}
// LoadImage loads an image into this runtime
func (r *CRIO) LoadImage(path string) error {
glog.Infof("Loading image: %s", path)

View File

@ -59,6 +59,9 @@ type Manager interface {
// Load an image idempotently into the runtime on a host
LoadImage(string) error
// ImageExists takes image name and image sha checks if an it exists
ImageExists(string, string) bool
// ListContainers returns a list of managed by this container runtime
ListContainers(string) ([]string, error)
// KillContainers removes containers based on ID

View File

@ -102,6 +102,20 @@ func (r *Docker) Disable() error {
return nil
}
// ImageExists checks if an image exists
func (r *Docker) ImageExists(name string, sha string) bool {
// expected output looks like [SHA_ALGO:SHA]
c := exec.Command("docker", "inspect", "--format='{{.Id}}'", name)
rr, err := r.Runner.RunCmd(c)
if err != nil {
return false
}
if !strings.Contains(rr.Output(), sha) {
return false
}
return true
}
// LoadImage loads an image into this runtime
func (r *Docker) LoadImage(path string) error {
glog.Infof("Loading image: %s", path)

View File

@ -18,14 +18,14 @@ package kubeconfig
import (
"io/ioutil"
"path/filepath"
"sync/atomic"
"time"
"github.com/golang/glog"
"github.com/juju/clock"
"github.com/juju/mutex"
"github.com/pkg/errors"
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/minikube/pkg/util/lock"
)
// Settings is the minikubes settings for kubeconfig
@ -119,8 +119,7 @@ func PopulateFromSettings(cfg *Settings, apiCfg *api.Config) error {
// activeContext is true when minikube is the CurrentContext
// If no CurrentContext is set, the given name will be used.
func Update(kcs *Settings) error {
// Add a lock around both the read, update, and write operations
spec := mutex.Spec{Name: "kubeconfigUpdate", Clock: clock.WallClock, Delay: 10 * time.Second}
spec := lock.PathMutexSpec(filepath.Join(kcs.filePath(), "settings.Update"))
glog.Infof("acquiring lock: %+v", spec)
releaser, err := mutex.Acquire(spec)
if err != nil {

View File

@ -23,7 +23,7 @@ import (
"k8s.io/client-go/util/homedir"
)
// MinikubeHome is the name of the minikube home directory variable.
// MinikubeHome is the name of the minikube home directory environment variable.
const MinikubeHome = "MINIKUBE_HOME"
// ConfigFile is the path of the config file
@ -46,3 +46,12 @@ func MakeMiniPath(fileName ...string) string {
args = append(args, fileName...)
return filepath.Join(args...)
}
// MachinePath returns the Minikube machine path of a machine
func MachinePath(machine string, miniHome ...string) string {
miniPath := MiniPath()
if len(miniHome) > 0 {
miniPath = miniHome[0]
}
return filepath.Join(miniPath, "machines", machine)
}

View File

@ -27,6 +27,7 @@ import (
"sync"
"time"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
@ -38,6 +39,7 @@ import (
"golang.org/x/sync/errgroup"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
@ -55,7 +57,10 @@ var loadImageLock sync.Mutex
// CacheImagesForBootstrapper will cache images for a bootstrapper
func CacheImagesForBootstrapper(imageRepository string, version string, clusterBootstrapper string) error {
images := bootstrapper.GetCachedImageList(imageRepository, version, clusterBootstrapper)
images, err := bootstrapper.GetCachedImageList(imageRepository, version, clusterBootstrapper)
if err != nil {
return errors.Wrap(err, "cached images list")
}
if err := CacheImages(images, constants.ImageCacheDir); err != nil {
return errors.Wrapf(err, "Caching images for %s", clusterBootstrapper)
@ -92,24 +97,38 @@ func CacheImages(images []string, cacheDir string) error {
}
// LoadImages loads previously cached images into the container runtime
func LoadImages(cmd command.Runner, images []string, cacheDir string) error {
func LoadImages(cc *config.MachineConfig, runner command.Runner, images []string, cacheDir string) error {
glog.Infof("LoadImages start: %s", images)
defer glog.Infof("LoadImages end")
var g errgroup.Group
// Load profile cluster config from file
cc, err := config.Load()
if err != nil && !os.IsNotExist(err) {
glog.Errorln("Error loading profile config: ", err)
cr, err := cruntime.New(cruntime.Config{Type: cc.ContainerRuntime, Runner: runner})
if err != nil {
return errors.Wrap(err, "runtime")
}
for _, image := range images {
image := image
g.Go(func() error {
src := filepath.Join(cacheDir, image)
src = sanitizeCacheDir(src)
if err := transferAndLoadImage(cmd, cc.KubernetesConfig, src); err != nil {
glog.Warningf("Failed to load %s: %v", src, err)
return errors.Wrapf(err, "loading image %s", src)
ref, err := name.ParseReference(image, name.WeakValidation)
if err != nil {
return errors.Wrap(err, "image name reference")
}
img, err := retrieveImage(ref)
if err != nil {
return errors.Wrap(err, "fetching image")
}
cf, err := img.ConfigName()
hash := cf.Hex
if err != nil {
glog.Infof("error retrieving image manifest for %s to check if it already exists: %v", image, err)
} else if cr.ImageExists(image, hash) {
glog.Infof("skipping re-loading image %q because sha %q already exists ", image, hash)
return nil
}
if err := transferAndLoadImage(runner, cc.KubernetesConfig, image, cacheDir); err != nil {
glog.Warningf("Failed to load %s: %v", image, err)
return errors.Wrapf(err, "loading image %s", image)
}
return nil
})
@ -121,7 +140,7 @@ func LoadImages(cmd command.Runner, images []string, cacheDir string) error {
return nil
}
// CacheAndLoadImages caches and loads images
// CacheAndLoadImages caches and loads images to all profiles
func CacheAndLoadImages(images []string) error {
if err := CacheImages(images, constants.ImageCacheDir); err != nil {
return err
@ -131,20 +150,38 @@ func CacheAndLoadImages(images []string) error {
return err
}
defer api.Close()
cc, err := config.Load()
profiles, _, err := config.ListProfiles() // need to load image to all profiles
if err != nil {
return err
return errors.Wrap(err, "list profiles")
}
h, err := api.Load(cc.Name)
if err != nil {
return err
for _, p := range profiles { // adding images to all the profiles
pName := p.Name // capture the loop variable
status, err := cluster.GetHostStatus(api, pName)
if err != nil {
glog.Warningf("skipping loading cache for profile %s", pName)
glog.Errorf("error getting status for %s: %v", pName, err)
continue // try next machine
}
if status == state.Running.String() { // the not running hosts will load on next start
h, err := api.Load(pName)
if err != nil {
return err
}
cr, err := CommandRunner(h)
if err != nil {
return err
}
c, err := config.Load(pName)
if err != nil {
return err
}
err = LoadImages(c, cr, images, constants.ImageCacheDir)
if err != nil {
glog.Warningf("Failed to load cached images for profile %s. make sure the profile is running. %v", pName, err)
}
}
}
runner, err := CommandRunner(h)
if err != nil {
return err
}
return LoadImages(runner, images, constants.ImageCacheDir)
return err
}
// # ParseReference cannot have a : in the directory path
@ -211,7 +248,13 @@ func getWindowsVolumeNameCmd(d string) (string, error) {
}
// transferAndLoadImage transfers and loads a single image from the cache
func transferAndLoadImage(cr command.Runner, k8s config.KubernetesConfig, src string) error {
func transferAndLoadImage(cr command.Runner, k8s config.KubernetesConfig, imgName string, cacheDir string) error {
r, err := cruntime.New(cruntime.Config{Type: k8s.ContainerRuntime, Runner: cr})
if err != nil {
return errors.Wrap(err, "runtime")
}
src := filepath.Join(cacheDir, imgName)
src = sanitizeCacheDir(src)
glog.Infof("Loading image from cache: %s", src)
filename := filepath.Base(src)
if _, err := os.Stat(src); err != nil {
@ -226,10 +269,6 @@ func transferAndLoadImage(cr command.Runner, k8s config.KubernetesConfig, src st
return errors.Wrap(err, "transferring cached image")
}
r, err := cruntime.New(cruntime.Config{Type: k8s.ContainerRuntime, Runner: cr})
if err != nil {
return errors.Wrap(err, "runtime")
}
loadImageLock.Lock()
defer loadImageLock.Unlock()
@ -331,6 +370,12 @@ func CacheImage(image, dst string) error {
if err != nil {
return err
}
defer func() { // clean up temp files
err := os.Remove(f.Name())
if err != nil {
glog.Infof("Failed to clean up the temp file %s : %v", f.Name(), err)
}
}()
tag, err := name.NewTag(image, name.WeakValidation)
if err != nil {
return err

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package machine
import (
"io/ioutil"
@ -23,8 +23,8 @@ import (
"github.com/docker/machine/libmachine/host"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
)
// Machine contains information about a machine
@ -60,15 +60,15 @@ func (h *Machine) IsValid() bool {
return true
}
// ListMachines return all valid and invalid machines
// List return all valid and invalid machines
// If a machine is valid or invalid is determined by the cluster.IsValid function
func ListMachines(miniHome ...string) (validMachines []*Machine, inValidMachines []*Machine, err error) {
func List(miniHome ...string) (validMachines []*Machine, inValidMachines []*Machine, err error) {
pDirs, err := machineDirs(miniHome...)
if err != nil {
return nil, nil, err
}
for _, n := range pDirs {
p, err := LoadMachine(n)
p, err := Load(n)
if err != nil {
glog.Infof("%s not valid: %v", n, err)
inValidMachines = append(inValidMachines, p)
@ -83,14 +83,14 @@ func ListMachines(miniHome ...string) (validMachines []*Machine, inValidMachines
return validMachines, inValidMachines, nil
}
// LoadMachine loads a machine or throws an error if the machine could not be loadedG
func LoadMachine(name string) (*Machine, error) {
api, err := machine.NewAPIClient()
// Load loads a machine or throws an error if the machine could not be loadedG
func Load(name string) (*Machine, error) {
api, err := NewAPIClient()
if err != nil {
return nil, err
}
h, err := CheckIfHostExistsAndLoad(api, name)
h, err := cluster.CheckIfHostExistsAndLoad(api, name)
if err != nil {
return nil, err
}
@ -119,12 +119,3 @@ func machineDirs(miniHome ...string) (dirs []string, err error) {
}
return dirs, err
}
// MachinePath returns the Minikube machine path of a machine
func MachinePath(machine string, miniHome ...string) string {
miniPath := localpath.MiniPath()
if len(miniHome) > 0 {
miniPath = miniHome[0]
}
return filepath.Join(miniPath, "machines", machine)
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package machine
import (
"io/ioutil"
@ -51,7 +51,7 @@ func TestListMachines(t *testing.T) {
files, _ := ioutil.ReadDir(filepath.Join(localpath.MiniPath(), "machines"))
numberOfMachineDirs := len(files)
validMachines, inValidMachines, err := ListMachines()
validMachines, inValidMachines, err := List()
if err != nil {
t.Error(err)

View File

@ -400,7 +400,7 @@ var osProblems = map[string]match{
// stateProblems are issues relating to local state
var stateProblems = map[string]match{
"MACHINE_DOES_NOT_EXST": {
"MACHINE_DOES_NOT_EXIST": {
Regexp: re(`Error getting state for host: machine does not exist`),
Advice: "Run 'minikube delete' to delete the stale VM",
Issues: []int{3864},

View File

@ -29,7 +29,7 @@ import (
func annotateDefaultStorageClass(storage storagev1.StorageV1Interface, class *v1.StorageClass, enable bool) error {
isDefault := strconv.FormatBool(enable)
metav1.SetMetaDataAnnotation(&class.ObjectMeta, "storageclass.beta.kubernetes.io/is-default-class", isDefault)
metav1.SetMetaDataAnnotation(&class.ObjectMeta, "storageclass.kubernetes.io/is-default-class", isDefault)
_, err := storage.StorageClasses().Update(class)
return err

View File

@ -314,7 +314,7 @@ func configureAuth(p *BuildrootProvisioner) error {
return err
}
config, err := config.Load()
config, err := config.Load(p.Driver.GetMachineName())
if err != nil {
return errors.Wrap(err, "getting cluster config")
}

View File

@ -17,12 +17,10 @@ limitations under the License.
package lock
import (
"crypto/sha1"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/golang/glog"
@ -33,51 +31,30 @@ import (
// WriteFile decorates ioutil.WriteFile with a file lock and retry
func WriteFile(filename string, data []byte, perm os.FileMode) error {
spec := mutex.Spec{
Name: getMutexName(filename),
Clock: clock.WallClock,
Delay: 13 * time.Second,
}
glog.Infof("attempting to write to file %q with filemode %v", filename, perm)
spec := PathMutexSpec(filename)
glog.Infof("WriteFile acquiring %s: %+v", filename, spec)
releaser, err := mutex.Acquire(spec)
if err != nil {
return errors.Wrapf(err, "error acquiring lock for %s", filename)
return errors.Wrapf(err, "failed to acquire lock for %s: %+v", filename, spec)
}
defer releaser.Release()
if err = ioutil.WriteFile(filename, data, perm); err != nil {
return errors.Wrapf(err, "error writing file %s", filename)
return errors.Wrapf(err, "writefile failed for %s", filename)
}
return err
}
func getMutexName(filename string) string {
// Make the mutex name the file name and its parent directory
dir, name := filepath.Split(filename)
// Replace underscores and periods with dashes, the only valid punctuation for mutex name
name = strings.ReplaceAll(name, ".", "-")
name = strings.ReplaceAll(name, "_", "-")
p := strings.ReplaceAll(filepath.Base(dir), ".", "-")
p = strings.ReplaceAll(p, "_", "-")
mutexName := fmt.Sprintf("%s-%s", p, strings.ReplaceAll(name, ".", "-"))
// Check if name starts with an int and prepend a string instead
if _, err := strconv.Atoi(mutexName[:1]); err == nil {
mutexName = "m" + mutexName
// PathMutexSpec returns a mutex spec for a path
func PathMutexSpec(path string) mutex.Spec {
s := mutex.Spec{
Name: fmt.Sprintf("mk%x", sha1.Sum([]byte(path)))[0:40],
Clock: clock.WallClock,
// Poll the lock twice a second
Delay: 500 * time.Millisecond,
// panic after a minute instead of locking infinitely
Timeout: 60 * time.Second,
}
// There's an arbitrary hard max on mutex name at 40.
if len(mutexName) > 40 {
mutexName = mutexName[:40]
}
// Make sure name doesn't start or end with punctuation
mutexName = strings.TrimPrefix(mutexName, "-")
mutexName = strings.TrimSuffix(mutexName, "-")
return mutexName
return s
}

View File

@ -16,9 +16,13 @@ limitations under the License.
package lock
import "testing"
import (
"testing"
func TestGetMutexName(t *testing.T) {
"github.com/juju/mutex"
)
func TestUserMutexSpec(t *testing.T) {
var tests = []struct {
description string
path string
@ -27,41 +31,53 @@ func TestGetMutexName(t *testing.T) {
{
description: "standard",
path: "/foo/bar",
expected: "foo-bar",
},
{
description: "deep directory",
path: "/foo/bar/baz/bat",
expected: "baz-bat",
},
{
description: "underscores",
path: "/foo_bar/baz",
expected: "foo-bar-baz",
},
{
description: "starts with number",
path: "/foo/2bar/baz",
expected: "m2bar-baz",
},
{
description: "starts with punctuation",
path: "/.foo/bar",
expected: "foo-bar",
},
{
description: "long filename",
path: "/very-very-very-very-very-very-very-very-long/bar",
expected: "very-very-very-very-very-very-very-very",
},
{
description: "Windows kubeconfig",
path: `C:\Users\admin/.kube/config`,
},
{
description: "Windows json",
path: `C:\Users\admin\.minikube\profiles\containerd-20191210T212325.7356633-8584\config.json`,
},
}
seen := map[string]string{}
for _, tc := range tests {
t.Run(tc.description, func(t *testing.T) {
got := getMutexName(tc.path)
if got != tc.expected {
t.Errorf("Unexpected mutex name for path %s. got: %s, expected: %s", tc.path, got, tc.expected)
got := PathMutexSpec(tc.path)
if len(got.Name) != 40 {
t.Errorf("%s is not 40 chars long", got.Name)
}
if seen[got.Name] != "" {
t.Fatalf("lock name collision between %s and %s", tc.path, seen[got.Name])
}
m, err := mutex.Acquire(got)
if err != nil {
t.Errorf("acquire for spec %+v failed: %v", got, err)
}
m.Release()
})
}
}

View File

@ -80,3 +80,22 @@ func TestConcatStrings(t *testing.T) {
}
}
}
func TestCalculateSizeInMB(t *testing.T) {
testData := []struct {
size string
expectedNumber int
}{
{"1024kb", 1},
{"1024KB", 1},
{"1024mb", 1024},
{"1024b", 0},
}
for _, tt := range testData {
number := CalculateSizeInMB(tt.size)
if number != tt.expectedNumber {
t.Fatalf("Expected '%d'' but got '%d'", tt.expectedNumber, number)
}
}
}

View File

@ -92,7 +92,7 @@ weight = 1
[params]
copyright = "The Kubernetes Authors -- "
# The latest release of minikube
latest_release = "1.5.2"
latest_release = "1.6.1"
privacy_policy = ""

View File

@ -5,13 +5,3 @@ weight: 4
description: >
Concepts that users and contributors should be aware of.
---
{{% pageinfo %}}
This is a placeholder page that shows you how to use this template site.
{{% /pageinfo %}}
For many projects, users may not need much information beyond the information in the [Overview](/docs/overview/), so this section is **optional**. However if there are areas where your users will need a more detailed understanding of a given term or feature in order to do anything useful with your project (or to not make mistakes when using it) put that information in this section. For example, you may want to add some conceptual pages if you have a large project with many components and a complex architecture.
Remember to focus on what the user needs to know, not just what you think is interesting about your project! If they dont need to understand your original design decisions to use or contribute to the project, dont put them in, or include your design docs in your repo and link to them. Similarly, most users will probably need to know more about how features work when in use rather than how they are implemented. Consider a separate architecture page for more detailed implementation and system design information that potential project contributors can consult.

View File

@ -11,7 +11,7 @@ Proper installation of KVM and libvirt is highly specific to each Linux distribu
* [Debian](https://wiki.debian.org/KVM#Installation)
* [Fedora](https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-virtualization/)
* [Gentoo](https://wiki.gentoo.org/wiki/QEMU)
* [OpenSUSE](https://doc.opensuse.org/documentation/leap/virtualization/html/book.virt/cha.vt.installation.html)
* [OpenSUSE](https://doc.opensuse.org/documentation/leap/virtualization/html/book.virt/cha-vt-installation.html)
* [RedHat](https://access.redhat.com/articles/1344173#Q_how-install-virtualization-packages)
* [Ubuntu](https://help.ubuntu.com/community/KVM/Installation)

View File

@ -0,0 +1,39 @@
---
title: "Audit Policy"
linkTitle: "Audit Policy"
weight: 1
date: 2019-11-19
description: >
Enabling audit policy for minikube
---
## Overview
[Auditing](https://kubernetes.io/docs/tasks/debug-application-cluster/audit/) is not enabled in minikube by default.
This tutorial shows how to provide an [Audit Policy](https://kubernetes.io/docs/tasks/debug-application-cluster/audit/#audit-policy) file to the minikube API server on startup.
## Tutorial
```shell
minikube stop
mkdir -p ~/.minikube/files/etc/ssl/certs
cat <<EOF > ~/.minikube/files/etc/ssl/certs/audit-policy.yaml
# Log all requests at the Metadata level.
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
EOF
minikube start \
--extra-config=apiserver.audit-policy-file=/etc/ssl/certs/audit-policy.yaml \
--extra-config=apiserver.audit-log-path=-
kubectl logs kube-apiserver-minikube -n kube-system | grep audit.k8s.io/v1
```
The [Audit Policy](https://kubernetes.io/docs/tasks/debug-application-cluster/audit/#audit-policy) used in this tutorial is very minimal and quite verbose. As a next step you might want to finetune the `audit-policy.yaml` file. To get the changes applied you need to stop and start minikube. Restarting minikube triggers the [file sync mechanism](https://minikube.sigs.k8s.io/docs/tasks/sync/) that copies the yaml file onto the minikube node and causes the API server to read the changed policy file.
Note: Currently there is no dedicated directory to store the `audit-policy.yaml` file in `~/.minikube/`. Using the `~/.minikube/files/etc/ssl/certs` directory is a workaround! This workaround works like this: By putting the file into a sub-directory of `~/.minikube/files/`, the [file sync mechanism](https://minikube.sigs.k8s.io/docs/tasks/sync/) gets triggered and copies the `audit-policy.yaml` file from the host onto the minikube node. When the API server container gets started by `kubeadm` I'll mount the `/etc/ssl/certs` directory from the minikube node into the container. This is the reason why the `audit-policy.yaml` file has to be stored in the ssl certs directory: It's one of the directories that get mounted from the minikube node into the container.

View File

@ -67,7 +67,11 @@ func TestDownloadOnly(t *testing.T) {
t.Errorf("%s failed: %v", args, err)
}
imgs := images.CachedImages("", v)
imgs, err := images.Kubeadm("", v)
if err != nil {
t.Errorf("kubeadm images: %v", 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)

View File

@ -38,7 +38,7 @@ func TestDockerFlags(t *testing.T) {
defer CleanupWithLogs(t, profile, cancel)
// Use the most verbose logging for the simplest test. If it fails, something is very wrong.
args := append([]string{"start", "-p", profile, "--wait=false", "--docker-env=FOO=BAR", "--docker-env=BAZ=BAT", "--docker-opt=debug", "--docker-opt=icc=true", "--alsologtostderr", "-v=5"}, StartArgs()...)
args := append([]string{"start", "-p", profile, "--cache-images=false", "--wait=false", "--docker-env=FOO=BAR", "--docker-env=BAZ=BAT", "--docker-opt=debug", "--docker-opt=icc=true", "--alsologtostderr", "-v=5"}, StartArgs()...)
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)

View File

@ -35,8 +35,13 @@ import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
"k8s.io/minikube/pkg/minikube/localpath"
"github.com/elazarl/goproxy"
"github.com/hashicorp/go-retryablehttp"
"github.com/otiai10/copy"
"github.com/phayes/freeport"
"github.com/pkg/errors"
"golang.org/x/build/kubernetes/api"
@ -59,6 +64,7 @@ func TestFunctional(t *testing.T) {
name string
validator validateFunc
}{
{"CopySyncFile", setupFileSync}, // Set file for the file sync test case
{"StartWithProxy", validateStartWithProxy}, // Set everything else up for success
{"KubeContext", validateKubeContext}, // Racy: must come immediately after "minikube start"
{"KubectlGetPods", validateKubectlGetPods}, // Make sure apiserver is up
@ -96,6 +102,8 @@ func TestFunctional(t *testing.T) {
{"TunnelCmd", validateTunnelCmd},
{"SSHCmd", validateSSHCmd},
{"MySQL", validateMySQL},
{"FileSync", validateFileSync},
{"UpdateContextCmd", validateUpdateContextCmd},
}
for _, tc := range tests {
tc := tc
@ -301,17 +309,51 @@ func validateDNS(ctx context.Context, t *testing.T, profile string) {
}
}
// validateCacheCmd asserts basic "ssh" command functionality
// validateCacheCmd tests functionality of cache command (cache add, delete, list)
func validateCacheCmd(ctx context.Context, t *testing.T, profile string) {
if NoneDriver() {
t.Skipf("skipping: cache unsupported by none")
}
for _, img := range []string{"busybox", "busybox:1.28.4-glibc", "mysql:5.6", "gcr.io/hello-minikube-zero-install/hello-node"} {
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "cache", "add", img))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
}
t.Run("cache", func(t *testing.T) {
t.Run("add", func(t *testing.T) {
for _, img := range []string{"busybox", "busybox:1.28.4-glibc", "k8s.gcr.io/pause:latest"} {
_, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "cache", "add", img))
if err != nil {
t.Errorf("Failed to cache image %q", img)
}
}
})
t.Run("delete", func(t *testing.T) {
_, err := Run(t, exec.CommandContext(ctx, Target(), "cache", "delete", "busybox:1.28.4-glibc"))
if err != nil {
t.Errorf("failed to delete image busybox:1.28.4-glibc from cache: %v", err)
}
})
t.Run("list", func(t *testing.T) {
rr, err := Run(t, exec.CommandContext(ctx, Target(), "cache", "list"))
if err != nil {
t.Errorf("cache list failed: %v", err)
}
if !strings.Contains(rr.Output(), "k8s.gcr.io/pause") {
t.Errorf("cache list did not include k8s.gcr.io/pause")
}
if strings.Contains(rr.Output(), "busybox:1.28.4-glibc") {
t.Errorf("cache list should not include busybox:1.28.4-glibc")
}
})
t.Run("verify cache inside node", func(t *testing.T) {
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", "sudo", "crictl", "images"))
if err != nil {
t.Errorf("failed to get docker images through ssh %v", err)
}
if !strings.Contains(rr.Output(), "1.28.4-glibc") {
t.Errorf("expected '1.28.4-glibc' to be in the output: %s", rr.Output())
}
})
})
}
// validateConfigCmd asserts basic "config" command functionality
@ -573,6 +615,50 @@ func validateMySQL(ctx context.Context, t *testing.T, profile string) {
}
}
// Copy extra file into minikube home folder for file sync test
func setupFileSync(ctx context.Context, t *testing.T, profile string) {
// 1. copy random file to MINIKUBE_HOME/files/etc
f := filepath.Join(localpath.MiniPath(), "/files/etc/sync.test")
err := copy.Copy("./testdata/sync.test", f)
if err != nil {
t.Fatalf("copy: %v", err)
}
}
// validateFileSync to check existence of the test file
func validateFileSync(ctx context.Context, t *testing.T, profile string) {
if NoneDriver() {
t.Skipf("skipping: ssh unsupported by none")
}
// check file existence
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", "cat /etc/sync.test"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
expected, err := ioutil.ReadFile("./testdata/sync.test")
if err != nil {
t.Errorf("test file not found: %v", err)
}
if diff := cmp.Diff(string(expected), rr.Stdout.String()); diff != "" {
t.Errorf("/etc/sync.test content mismatch (-want +got):\n%s", diff)
}
}
// validateUpdateContextCmd asserts basic "update-context" command functionality
func validateUpdateContextCmd(ctx context.Context, t *testing.T, profile string) {
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "update-context", "--alsologtostderr", "-v=2"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
want := []byte("IP was already correctly configured")
if !bytes.Contains(rr.Stdout.Bytes(), want) {
t.Errorf("update-context: got=%q, want=*%q*", rr.Stdout.Bytes(), want)
}
}
// startHTTPProxy runs a local http proxy and sets the env vars for it.
func startHTTPProxy(t *testing.T) (*http.Server, error) {
port, err := freeport.GetFreePort()

View File

@ -20,15 +20,19 @@ package integration
import (
"context"
"encoding/json"
"fmt"
"os/exec"
"path/filepath"
"sort"
"strconv"
"strings"
"testing"
"time"
"github.com/docker/machine/libmachine/state"
"github.com/google/go-cmp/cmp"
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
"k8s.io/minikube/pkg/minikube/constants"
)
@ -37,12 +41,11 @@ func TestStartStop(t *testing.T) {
t.Run("group", func(t *testing.T) {
tests := []struct {
name string
args []string
name string
version string
args []string
}{
{"docker", []string{
"--cache-images=false",
fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion),
{"old-docker", constants.OldestKubernetesVersion, []string{
// default is the network created by libvirt, if we change the name minikube won't boot
// because the given network doesn't exist
"--kvm-network=default",
@ -51,21 +54,20 @@ func TestStartStop(t *testing.T) {
"--keep-context=false",
"--container-runtime=docker",
}},
{"cni", []string{
{"newest-cni", constants.NewestKubernetesVersion, []string{
"--feature-gates",
"ServerSideApply=true",
"--network-plugin=cni",
"--extra-config=kubelet.network-plugin=cni",
"--extra-config=kubeadm.pod-network-cidr=192.168.111.111/16",
fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion),
}},
{"containerd", []string{
{"containerd", constants.DefaultKubernetesVersion, []string{
"--container-runtime=containerd",
"--docker-opt",
"containerd=/var/run/containerd/containerd.sock",
"--apiserver-port=8444",
}},
{"crio", []string{
{"crio", "v1.15.0", []string{
"--container-runtime=crio",
"--disable-driver-mounts",
"--extra-config=kubeadm.ignore-preflight-errors=SystemVerification",
@ -88,6 +90,7 @@ func TestStartStop(t *testing.T) {
startArgs := append([]string{"start", "-p", profile, "--alsologtostderr", "-v=3", "--wait=true"}, tc.args...)
startArgs = append(startArgs, StartArgs()...)
startArgs = append(startArgs, fmt.Sprintf("--kubernetes-version=%s", tc.version))
rr, err := Run(t, exec.CommandContext(ctx, Target(), startArgs...))
if err != nil {
// Fatal so that we may collect logs before stop/delete steps
@ -144,6 +147,40 @@ func TestStartStop(t *testing.T) {
t.Fatalf("%s failed: %v", rr.Args, err)
}
// Make sure that kubeadm did not need to pull in additional images
if !NoneDriver() {
rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "sudo crictl images -o json"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
jv := map[string][]struct {
Tags []string `json:"repoTags"`
}{}
err = json.Unmarshal(rr.Stdout.Bytes(), &jv)
if err != nil {
t.Errorf("images unmarshal: %v", err)
}
gotImages := []string{}
for _, img := range jv["images"] {
for _, i := range img.Tags {
// Ignore non-Kubernetes images
if !strings.Contains(i, "ingress") && !strings.Contains(i, "busybox") {
// Remove docker.io for naming consistency between container runtimes
gotImages = append(gotImages, strings.TrimPrefix(i, "docker.io/"))
}
}
}
want, err := images.Kubeadm("", tc.version)
if err != nil {
t.Errorf("kubeadm images: %v", tc.version)
}
sort.Strings(want)
sort.Strings(gotImages)
if diff := cmp.Diff(want, gotImages); diff != "" {
t.Errorf("%s images mismatch (-want +got):\n%s", tc.version, diff)
}
}
if strings.Contains(tc.name, "cni") {
t.Logf("WARNING: cni mode requires additional setup before pods can schedule :(")
} else if _, err := PodWait(ctx, t, profile, "default", "integration-test=busybox", 2*time.Minute); err != nil {
@ -155,7 +192,7 @@ func TestStartStop(t *testing.T) {
t.Errorf("status = %q; want = %q", got, state.Running)
}
if !*cleanup {
if *cleanup {
// Normally handled by cleanuprofile, but not fatal there
rr, err = Run(t, exec.CommandContext(ctx, Target(), "delete", "-p", profile))
if err != nil {

1
test/integration/testdata/sync.test vendored Normal file
View File

@ -0,0 +1 @@
Test file for checking file sync process

View File

@ -18,6 +18,7 @@ package integration
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
@ -28,6 +29,7 @@ import (
"time"
"github.com/docker/machine/libmachine/state"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util/retry"
@ -66,13 +68,13 @@ func TestVersionUpgrade(t *testing.T) {
args := append([]string{"start", "-p", profile, fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion), "--alsologtostderr", "-v=1"}, StartArgs()...)
rr := &RunResult{}
releaseStart := func() error {
r := func() error {
rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
return err
}
// Retry to allow flakiness for the previous release
if err := retry.Expo(releaseStart, 1*time.Second, 30*time.Minute, 3); err != nil {
if err := retry.Expo(r, 1*time.Second, 30*time.Minute, 3); err != nil {
t.Fatalf("release start failed: %v", err)
}
@ -96,4 +98,34 @@ func TestVersionUpgrade(t *testing.T) {
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
s, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "version", "--output=json"))
if err != nil {
t.Fatalf("error running kubectl: %v", err)
}
cv := struct {
ServerVersion struct {
GitVersion string `json:"gitVersion"`
} `json:"serverVersion"`
}{}
err = json.Unmarshal(s.Stdout.Bytes(), &cv)
if err != nil {
t.Fatalf("error traversing json output: %v", err)
}
if cv.ServerVersion.GitVersion != constants.NewestKubernetesVersion {
t.Fatalf("expected server version %s is not the same with latest version %s", cv.ServerVersion.GitVersion, constants.NewestKubernetesVersion)
}
args = append([]string{"start", "-p", profile, fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion), "--alsologtostderr", "-v=1"}, StartArgs()...)
rr = &RunResult{}
r = func() error {
rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
return err
}
if err := retry.Expo(r, 1*time.Second, 30*time.Minute, 3); err == nil {
t.Fatalf("downgrading kubernetes should not be allowed: %v", err)
}
}