commit
be196bfe9d
|
@ -64,11 +64,6 @@ jobs:
|
||||||
echo workspace $GITHUB_WORKSPACE
|
echo workspace $GITHUB_WORKSPACE
|
||||||
echo "end of debug stuff"
|
echo "end of debug stuff"
|
||||||
echo $(which jq)
|
echo $(which jq)
|
||||||
# iso needs golang 1.11.3
|
|
||||||
- uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: '1.11.13'
|
|
||||||
stable: true
|
|
||||||
- name: Build ISO
|
- name: Build ISO
|
||||||
run: |
|
run: |
|
||||||
whoami
|
whoami
|
||||||
|
|
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -1,5 +1,31 @@
|
||||||
# Release Notes
|
# Release Notes
|
||||||
|
|
||||||
|
## Version 1.13.1 - 2020-09-18
|
||||||
|
* Update Default Kubernetes Version to v1.19.2 [#9265](https://github.com/kubernetes/minikube/pull/9265)
|
||||||
|
* fix mounting for docker driver in windows [#9263](https://github.com/kubernetes/minikube/pull/9263)
|
||||||
|
* CSI Hostpath Driver & VolumeSnapshots addons [#8461](https://github.com/kubernetes/minikube/pull/8461)
|
||||||
|
* docker/podman drivers: Make sure CFS_BANDWIDTH is available for --cpus [#9255](https://github.com/kubernetes/minikube/pull/9255)
|
||||||
|
* Fix ForwardedPort for podman version 2.0.1 and up [#9237](https://github.com/kubernetes/minikube/pull/9237)
|
||||||
|
* Avoid setting time for memory assets [#9256](https://github.com/kubernetes/minikube/pull/9256)
|
||||||
|
* point to newest gcp-auth-webhook version [#9199](https://github.com/kubernetes/minikube/pull/9199)
|
||||||
|
* Set preload=false if not using overlay2 as docker storage driver [#8831](https://github.com/kubernetes/minikube/pull/8831)
|
||||||
|
* Upgrade crio to 1.17.3 [#8922](https://github.com/kubernetes/minikube/pull/8922)
|
||||||
|
* Add Docker Desktop instructions if memory is greater than minimum but less than recommended [#9181](https://github.com/kubernetes/minikube/pull/9181)
|
||||||
|
* Update minimum memory constants to use MiB instead of MB [#9180](https://github.com/kubernetes/minikube/pull/9180)
|
||||||
|
|
||||||
|
Thank you to our contributors for this release!
|
||||||
|
- Anders F Björklund
|
||||||
|
- Dean Coakley
|
||||||
|
- Julien Breux
|
||||||
|
- Li Zhijian
|
||||||
|
- Medya Ghazizadeh
|
||||||
|
- Priya Wadhwa
|
||||||
|
- Sharif Elgamal
|
||||||
|
- Thomas Strömberg
|
||||||
|
- Zadjad Rezai
|
||||||
|
- jjanik
|
||||||
|
|
||||||
|
|
||||||
## Version 1.13.0 - 2020-09-03
|
## Version 1.13.0 - 2020-09-03
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
22
Makefile
22
Makefile
|
@ -15,7 +15,7 @@
|
||||||
# Bump these on release - and please check ISO_VERSION for correctness.
|
# Bump these on release - and please check ISO_VERSION for correctness.
|
||||||
VERSION_MAJOR ?= 1
|
VERSION_MAJOR ?= 1
|
||||||
VERSION_MINOR ?= 13
|
VERSION_MINOR ?= 13
|
||||||
VERSION_BUILD ?= 0
|
VERSION_BUILD ?= 1
|
||||||
RAW_VERSION=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD)
|
RAW_VERSION=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD)
|
||||||
VERSION ?= v$(RAW_VERSION)
|
VERSION ?= v$(RAW_VERSION)
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ KUBERNETES_VERSION ?= $(shell egrep "DefaultKubernetesVersion =" pkg/minikube/co
|
||||||
KIC_VERSION ?= $(shell egrep "Version =" pkg/drivers/kic/types.go | cut -d \" -f2)
|
KIC_VERSION ?= $(shell egrep "Version =" pkg/drivers/kic/types.go | cut -d \" -f2)
|
||||||
|
|
||||||
# Default to .0 for higher cache hit rates, as build increments typically don't require new ISO versions
|
# Default to .0 for higher cache hit rates, as build increments typically don't require new ISO versions
|
||||||
ISO_VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).0
|
ISO_VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).1
|
||||||
# Dashes are valid in semver, but not Linux packaging. Use ~ to delimit alpha/beta
|
# Dashes are valid in semver, but not Linux packaging. Use ~ to delimit alpha/beta
|
||||||
DEB_VERSION ?= $(subst -,~,$(RAW_VERSION))
|
DEB_VERSION ?= $(subst -,~,$(RAW_VERSION))
|
||||||
RPM_VERSION ?= $(DEB_VERSION)
|
RPM_VERSION ?= $(DEB_VERSION)
|
||||||
|
@ -305,9 +305,15 @@ html_report: ## Generate HTML report out of the last ran integration test logs.
|
||||||
@go tool test2json -t < "./out/testout_$(COMMIT_SHORT).txt" > "./out/testout_$(COMMIT_SHORT).json"
|
@go tool test2json -t < "./out/testout_$(COMMIT_SHORT).txt" > "./out/testout_$(COMMIT_SHORT).json"
|
||||||
@gopogh -in "./out/testout_$(COMMIT_SHORT).json" -out ./out/testout_$(COMMIT_SHORT).html -name "$(shell git rev-parse --abbrev-ref HEAD)" -pr "" -repo github.com/kubernetes/minikube/ -details "${COMMIT_SHORT}"
|
@gopogh -in "./out/testout_$(COMMIT_SHORT).json" -out ./out/testout_$(COMMIT_SHORT).html -name "$(shell git rev-parse --abbrev-ref HEAD)" -pr "" -repo github.com/kubernetes/minikube/ -details "${COMMIT_SHORT}"
|
||||||
@echo "-------------------------- Open HTML Report in Browser: ---------------------------"
|
@echo "-------------------------- Open HTML Report in Browser: ---------------------------"
|
||||||
|
ifeq ($(GOOS),windows)
|
||||||
|
@echo start $(CURDIR)/out/testout_$(COMMIT_SHORT).html
|
||||||
|
@echo "-----------------------------------------------------------------------------------"
|
||||||
|
@start $(CURDIR)/out/testout_$(COMMIT_SHORT).html || true
|
||||||
|
else
|
||||||
@echo open $(CURDIR)/out/testout_$(COMMIT_SHORT).html
|
@echo open $(CURDIR)/out/testout_$(COMMIT_SHORT).html
|
||||||
@echo "-----------------------------------------------------------------------------------"
|
@echo "-----------------------------------------------------------------------------------"
|
||||||
@open $(CURDIR)/out/testout_$(COMMIT_SHORT).html || true
|
@open $(CURDIR)/out/testout_$(COMMIT_SHORT).html || true
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go ## Trigger minikube test
|
test: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go ## Trigger minikube test
|
||||||
|
@ -331,7 +337,7 @@ pkg/minikube/assets/assets.go: $(shell find "deploy/addons" -type f)
|
||||||
ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y)
|
ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y)
|
||||||
$(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@)
|
$(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@)
|
||||||
endif
|
endif
|
||||||
@which go-bindata >/dev/null 2>&1 || GO111MODULE=off GOBIN="$(GOPATH)$(DIRSEP)bin" go get github.com/jteeuwen/go-bindata/...
|
@which go-bindata >/dev/null 2>&1 || GO111MODULE=off GOBIN="$(GOPATH)$(DIRSEP)bin" go get github.com/go-bindata/go-bindata/...
|
||||||
$(if $(quiet),@echo " GEN $@")
|
$(if $(quiet),@echo " GEN $@")
|
||||||
$(Q)PATH="$(PATH)$(PATHSEP)$(GOPATH)$(DIRSEP)bin" go-bindata -nomemcopy -o $@ -pkg assets deploy/addons/...
|
$(Q)PATH="$(PATH)$(PATHSEP)$(GOPATH)$(DIRSEP)bin" go-bindata -nomemcopy -o $@ -pkg assets deploy/addons/...
|
||||||
$(Q)-gofmt -s -w $@
|
$(Q)-gofmt -s -w $@
|
||||||
|
@ -344,7 +350,7 @@ pkg/minikube/translate/translations.go: $(shell find "translations/" -type f)
|
||||||
ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y)
|
ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y)
|
||||||
$(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@)
|
$(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@)
|
||||||
endif
|
endif
|
||||||
@which go-bindata >/dev/null 2>&1 || GO111MODULE=off GOBIN="$(GOPATH)$(DIRSEP)bin" go get github.com/jteeuwen/go-bindata/...
|
@which go-bindata >/dev/null 2>&1 || GO111MODULE=off GOBIN="$(GOPATH)$(DIRSEP)bin" go get github.com/go-bindata/go-bindata/...
|
||||||
$(if $(quiet),@echo " GEN $@")
|
$(if $(quiet),@echo " GEN $@")
|
||||||
$(Q)PATH="$(PATH)$(PATHSEP)$(GOPATH)$(DIRSEP)bin" go-bindata -nomemcopy -o $@ -pkg translate translations/...
|
$(Q)PATH="$(PATH)$(PATHSEP)$(GOPATH)$(DIRSEP)bin" go-bindata -nomemcopy -o $@ -pkg translate translations/...
|
||||||
$(Q)-gofmt -s -w $@
|
$(Q)-gofmt -s -w $@
|
||||||
|
@ -579,7 +585,7 @@ storage-provisioner-image: out/storage-provisioner-$(GOARCH) ## Build storage-pr
|
||||||
.PHONY: kic-base-image
|
.PHONY: kic-base-image
|
||||||
kic-base-image: ## builds the base image used for kic.
|
kic-base-image: ## builds the base image used for kic.
|
||||||
docker rmi -f $(KIC_BASE_IMAGE_GCR)-snapshot || true
|
docker rmi -f $(KIC_BASE_IMAGE_GCR)-snapshot || true
|
||||||
docker build -f ./deploy/kicbase/Dockerfile -t local/kicbase:$(KIC_VERSION)-snapshot --build-arg COMMIT_SHA=${VERSION}-$(COMMIT) --cache-from $(KIC_BASE_IMAGE_GCR) --target base ./deploy/kicbase
|
docker build -f ./deploy/kicbase/Dockerfile -t local/kicbase:$(KIC_VERSION)-snapshot --build-arg COMMIT_SHA=${VERSION}-$(COMMIT) --cache-from $(KIC_BASE_IMAGE_GCR) ./deploy/kicbase
|
||||||
docker tag local/kicbase:$(KIC_VERSION)-snapshot $(KIC_BASE_IMAGE_GCR)-snapshot
|
docker tag local/kicbase:$(KIC_VERSION)-snapshot $(KIC_BASE_IMAGE_GCR)-snapshot
|
||||||
docker tag local/kicbase:$(KIC_VERSION)-snapshot $(KIC_BASE_IMAGE_GCR)
|
docker tag local/kicbase:$(KIC_VERSION)-snapshot $(KIC_BASE_IMAGE_GCR)
|
||||||
docker tag local/kicbase:$(KIC_VERSION)-snapshot $(KIC_BASE_IMAGE_HUB)
|
docker tag local/kicbase:$(KIC_VERSION)-snapshot $(KIC_BASE_IMAGE_HUB)
|
||||||
|
@ -747,9 +753,9 @@ site: site/themes/docsy/assets/vendor/bootstrap/package.js out/hugo/hugo ## Serv
|
||||||
out/mkcmp:
|
out/mkcmp:
|
||||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/mkcmp/main.go
|
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/mkcmp/main.go
|
||||||
|
|
||||||
.PHONY: out/performance-monitor
|
.PHONY: out/performance-bot
|
||||||
out/performance-monitor:
|
out/performance-bot:
|
||||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/monitor/monitor.go
|
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/pr-bot/bot.go
|
||||||
|
|
||||||
.PHONY: compare
|
.PHONY: compare
|
||||||
compare: out/mkcmp out/minikube
|
compare: out/mkcmp out/minikube
|
||||||
|
|
|
@ -28,8 +28,7 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/reason"
|
"k8s.io/minikube/pkg/minikube/reason"
|
||||||
)
|
)
|
||||||
|
|
||||||
const longDescription = `
|
const longDescription = `Outputs minikube shell completion for the given shell (bash, zsh or fish)
|
||||||
Outputs minikube shell completion for the given shell (bash, zsh or fish)
|
|
||||||
|
|
||||||
This depends on the bash-completion binary. Example installation instructions:
|
This depends on the bash-completion binary. Example installation instructions:
|
||||||
OS X:
|
OS X:
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/kverify"
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
"k8s.io/minikube/pkg/minikube/driver"
|
"k8s.io/minikube/pkg/minikube/driver"
|
||||||
"k8s.io/minikube/pkg/minikube/exit"
|
"k8s.io/minikube/pkg/minikube/exit"
|
||||||
|
@ -31,6 +32,7 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/reason"
|
"k8s.io/minikube/pkg/minikube/reason"
|
||||||
"k8s.io/minikube/pkg/minikube/style"
|
"k8s.io/minikube/pkg/minikube/style"
|
||||||
|
|
||||||
|
"github.com/docker/machine/libmachine"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -54,96 +56,114 @@ var profileListCmd = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var printProfilesTable = func() {
|
func printProfilesTable() {
|
||||||
var validData [][]string
|
validProfiles, invalidProfiles, err := config.ListProfiles()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("error loading profiles: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(validProfiles) == 0 {
|
||||||
|
exit.Message(reason.Usage, "No minikube profile was found. You can create one using `minikube start`.")
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProfilesStatus(validProfiles)
|
||||||
|
renderProfilesTable(profilesToTableData(validProfiles))
|
||||||
|
warnInvalidProfiles(invalidProfiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateProfilesStatus(profiles []*config.Profile) {
|
||||||
|
api, err := machine.NewAPIClient()
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("failed to get machine api client %v", err)
|
||||||
|
}
|
||||||
|
defer api.Close()
|
||||||
|
|
||||||
|
for _, p := range profiles {
|
||||||
|
p.Status = profileStatus(p, api)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func profileStatus(p *config.Profile, api libmachine.API) string {
|
||||||
|
cp, err := config.PrimaryControlPlane(p.Config)
|
||||||
|
if err != nil {
|
||||||
|
exit.Error(reason.GuestCpConfig, "error getting primary control plane", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := machine.LoadHost(api, driver.MachineName(*p.Config, cp))
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("error loading profiles: %v", err)
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
cr, err := machine.CommandRunner(host)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("error loading profiles: %v", err)
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname, _, port, err := driver.ControlPlaneEndpoint(p.Config, &cp, host.DriverName)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("error loading profiles: %v", err)
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := kverify.APIServerStatus(cr, hostname, port)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("error getting apiserver status for %s: %v", p.Name, err)
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
return status.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderProfilesTable(ps [][]string) {
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
table.SetHeader([]string{"Profile", "VM Driver", "Runtime", "IP", "Port", "Version", "Status"})
|
table.SetHeader([]string{"Profile", "VM Driver", "Runtime", "IP", "Port", "Version", "Status"})
|
||||||
table.SetAutoFormatHeaders(false)
|
table.SetAutoFormatHeaders(false)
|
||||||
table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true})
|
table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true})
|
||||||
table.SetCenterSeparator("|")
|
table.SetCenterSeparator("|")
|
||||||
validProfiles, invalidProfiles, err := config.ListProfiles()
|
table.AppendBulk(ps)
|
||||||
|
table.Render()
|
||||||
if len(validProfiles) == 0 || err != nil {
|
|
||||||
exit.Message(reason.Usage, "No minikube profile was found. You can create one using `minikube start`.")
|
|
||||||
}
|
}
|
||||||
api, err := machine.NewAPIClient()
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("failed to get machine api client %v", err)
|
|
||||||
}
|
|
||||||
defer api.Close()
|
|
||||||
|
|
||||||
for _, p := range validProfiles {
|
func profilesToTableData(profiles []*config.Profile) [][]string {
|
||||||
|
var data [][]string
|
||||||
|
for _, p := range profiles {
|
||||||
cp, err := config.PrimaryControlPlane(p.Config)
|
cp, err := config.PrimaryControlPlane(p.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit.Error(reason.GuestCpConfig, "error getting primary control plane", err)
|
exit.Error(reason.GuestCpConfig, "error getting primary control plane", err)
|
||||||
}
|
}
|
||||||
p.Status, err = machine.Status(api, driver.MachineName(*p.Config, cp))
|
|
||||||
if err != nil {
|
data = append(data, []string{p.Name, p.Config.Driver, p.Config.KubernetesConfig.ContainerRuntime, cp.IP, strconv.Itoa(cp.Port), p.Config.KubernetesConfig.KubernetesVersion, p.Status})
|
||||||
glog.Warningf("error getting host status for %s: %v", p.Name, err)
|
|
||||||
}
|
}
|
||||||
validData = append(validData, []string{p.Name, p.Config.Driver, p.Config.KubernetesConfig.ContainerRuntime, cp.IP, strconv.Itoa(cp.Port), p.Config.KubernetesConfig.KubernetesVersion, p.Status})
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
table.AppendBulk(validData)
|
func warnInvalidProfiles(invalidProfiles []*config.Profile) {
|
||||||
table.Render()
|
if invalidProfiles == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if invalidProfiles != nil {
|
|
||||||
out.WarningT("Found {{.number}} invalid profile(s) ! ", out.V{"number": len(invalidProfiles)})
|
out.WarningT("Found {{.number}} invalid profile(s) ! ", out.V{"number": len(invalidProfiles)})
|
||||||
for _, p := range invalidProfiles {
|
for _, p := range invalidProfiles {
|
||||||
out.ErrT(style.Empty, "\t "+p.Name)
|
out.ErrT(style.Empty, "\t "+p.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
out.ErrT(style.Tip, "You can delete them using the following command(s): ")
|
out.ErrT(style.Tip, "You can delete them using the following command(s): ")
|
||||||
for _, p := range invalidProfiles {
|
for _, p := range invalidProfiles {
|
||||||
out.Err(fmt.Sprintf("\t $ minikube delete -p %s \n", p.Name))
|
out.Err(fmt.Sprintf("\t $ minikube delete -p %s \n", p.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
func printProfilesJSON() {
|
||||||
glog.Warningf("error loading profiles: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var printProfilesJSON = func() {
|
|
||||||
api, err := machine.NewAPIClient()
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("failed to get machine api client %v", err)
|
|
||||||
}
|
|
||||||
defer api.Close()
|
|
||||||
|
|
||||||
validProfiles, invalidProfiles, err := config.ListProfiles()
|
validProfiles, invalidProfiles, err := config.ListProfiles()
|
||||||
for _, v := range validProfiles {
|
|
||||||
cp, err := config.PrimaryControlPlane(v.Config)
|
|
||||||
if err != nil {
|
|
||||||
exit.Error(reason.GuestCpConfig, "error getting primary control plane", err)
|
|
||||||
}
|
|
||||||
status, err := machine.Status(api, driver.MachineName(*v.Config, cp))
|
|
||||||
if err != nil {
|
|
||||||
glog.Warningf("error getting host status for %s: %v", v.Name, err)
|
|
||||||
}
|
|
||||||
v.Status = status
|
|
||||||
}
|
|
||||||
|
|
||||||
var valid []*config.Profile
|
updateProfilesStatus(validProfiles)
|
||||||
var invalid []*config.Profile
|
|
||||||
|
|
||||||
if validProfiles != nil {
|
|
||||||
valid = validProfiles
|
|
||||||
} else {
|
|
||||||
valid = []*config.Profile{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if invalidProfiles != nil {
|
|
||||||
invalid = invalidProfiles
|
|
||||||
} else {
|
|
||||||
invalid = []*config.Profile{}
|
|
||||||
}
|
|
||||||
|
|
||||||
body := map[string]interface{}{}
|
|
||||||
|
|
||||||
|
var body = map[string]interface{}{}
|
||||||
if err == nil || config.IsNotExist(err) {
|
if err == nil || config.IsNotExist(err) {
|
||||||
body["valid"] = valid
|
body["valid"] = profilesOrDefault(validProfiles)
|
||||||
body["invalid"] = invalid
|
body["invalid"] = profilesOrDefault(invalidProfiles)
|
||||||
jsonString, _ := json.Marshal(body)
|
jsonString, _ := json.Marshal(body)
|
||||||
out.String(string(jsonString))
|
out.String(string(jsonString))
|
||||||
} else {
|
} else {
|
||||||
|
@ -154,6 +174,13 @@ var printProfilesJSON = func() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func profilesOrDefault(profiles []*config.Profile) []*config.Profile {
|
||||||
|
if profiles != nil {
|
||||||
|
return profiles
|
||||||
|
}
|
||||||
|
return []*config.Profile{}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
profileListCmd.Flags().StringVarP(&output, "output", "o", "table", "The output format. One of 'json', 'table'")
|
profileListCmd.Flags().StringVarP(&output, "output", "o", "table", "The output format. One of 'json', 'table'")
|
||||||
ProfileCmd.AddCommand(profileListCmd)
|
ProfileCmd.AddCommand(profileListCmd)
|
||||||
|
|
|
@ -91,7 +91,6 @@ func init() {
|
||||||
if err := viper.BindPFlags(deleteCmd.Flags()); err != nil {
|
if err := viper.BindPFlags(deleteCmd.Flags()); err != nil {
|
||||||
exit.Error(reason.InternalBindFlags, "unable to bind flags", err)
|
exit.Error(reason.InternalBindFlags, "unable to bind flags", err)
|
||||||
}
|
}
|
||||||
RootCmd.AddCommand(deleteCmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// shotgun cleanup to delete orphaned docker container data
|
// shotgun cleanup to delete orphaned docker container data
|
||||||
|
@ -261,6 +260,11 @@ func deletePossibleKicLeftOver(cname string, driverName string) {
|
||||||
glog.Warningf("error deleting volumes (might be okay).\nTo see the list of volumes run: 'docker volume ls'\n:%v", errs)
|
glog.Warningf("error deleting volumes (might be okay).\nTo see the list of volumes run: 'docker volume ls'\n:%v", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errs = oci.DeleteKICNetworks()
|
||||||
|
if errs != nil {
|
||||||
|
glog.Warningf("error deleting leftover networks (might be okay).\nTo see the list of networks: 'docker network ls'\n:%v", errs)
|
||||||
|
}
|
||||||
|
|
||||||
if bin == oci.Podman {
|
if bin == oci.Podman {
|
||||||
// podman prune does not support --filter
|
// podman prune does not support --filter
|
||||||
return
|
return
|
||||||
|
|
|
@ -110,7 +110,7 @@ var mountCmd = &cobra.Command{
|
||||||
var ip net.IP
|
var ip net.IP
|
||||||
var err error
|
var err error
|
||||||
if mountIP == "" {
|
if mountIP == "" {
|
||||||
ip, err = cluster.HostIP(co.CP.Host)
|
ip, err = cluster.HostIP(co.CP.Host, co.Config.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit.Error(reason.IfHostIP, "Error getting the host IP address to use from within the VM", err)
|
exit.Error(reason.IfHostIP, "Error getting the host IP address to use from within the VM", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import (
|
||||||
gopshost "github.com/shirou/gopsutil/host"
|
gopshost "github.com/shirou/gopsutil/host"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
|
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
|
||||||
"k8s.io/minikube/pkg/drivers/kic/oci"
|
"k8s.io/minikube/pkg/drivers/kic/oci"
|
||||||
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil"
|
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil"
|
||||||
|
@ -156,9 +157,14 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
out.WarningT("Profile name '{{.name}}' is not valid", out.V{"name": ClusterFlagValue()})
|
out.WarningT("Profile name '{{.name}}' is not valid", out.V{"name": ClusterFlagValue()})
|
||||||
exit.Message(reason.Usage, "Only alphanumeric and dashes '-' are permitted. Minimum 1 character, starting with alphanumeric.")
|
exit.Message(reason.Usage, "Only alphanumeric and dashes '-' are permitted. Minimum 1 character, starting with alphanumeric.")
|
||||||
}
|
}
|
||||||
|
|
||||||
existing, err := config.Load(ClusterFlagValue())
|
existing, err := config.Load(ClusterFlagValue())
|
||||||
if err != nil && !config.IsNotExist(err) {
|
if err != nil && !config.IsNotExist(err) {
|
||||||
exit.Message(reason.HostConfigLoad, "Unable to load config: {{.error}}", out.V{"error": err})
|
kind := reason.HostConfigLoad
|
||||||
|
if config.IsPermissionDenied(err) {
|
||||||
|
kind = reason.HostHomePermission
|
||||||
|
}
|
||||||
|
exit.Message(kind, "Unable to load config: {{.error}}", out.V{"error": err})
|
||||||
}
|
}
|
||||||
|
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
|
@ -167,7 +173,24 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
validateSpecifiedDriver(existing)
|
validateSpecifiedDriver(existing)
|
||||||
validateKubernetesVersion(existing)
|
validateKubernetesVersion(existing)
|
||||||
|
|
||||||
ds, alts, specified := selectDriver(existing)
|
ds, alts, specified := selectDriver(existing)
|
||||||
|
if cmd.Flag(kicBaseImage).Changed {
|
||||||
|
if !isBaseImageApplicable(ds.Name) {
|
||||||
|
exit.Message(reason.Usage,
|
||||||
|
"flag --{{.imgFlag}} is not available for driver '{{.driver}}'. Did you mean to use '{{.docker}}' or '{{.podman}}' driver instead?\n"+
|
||||||
|
"Please use --{{.isoFlag}} flag to configure VM based drivers",
|
||||||
|
out.V{
|
||||||
|
"imgFlag": kicBaseImage,
|
||||||
|
"driver": ds.Name,
|
||||||
|
"docker": registry.Docker,
|
||||||
|
"podman": registry.Podman,
|
||||||
|
"isoFlag": isoURL,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
starter, err := provisionWithDriver(cmd, ds, existing)
|
starter, err := provisionWithDriver(cmd, ds, existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
node.ExitIfFatal(err)
|
node.ExitIfFatal(err)
|
||||||
|
@ -516,6 +539,7 @@ func kubectlVersion(path string) (string, error) {
|
||||||
return cv.ClientVersion.GitVersion, nil
|
return cv.ClientVersion.GitVersion, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns (current_driver, suggested_drivers, "true, if the driver is set by command line arg or in the config file")
|
||||||
func selectDriver(existing *config.ClusterConfig) (registry.DriverState, []registry.DriverState, bool) {
|
func selectDriver(existing *config.ClusterConfig) (registry.DriverState, []registry.DriverState, bool) {
|
||||||
// Technically unrelated, but important to perform before detection
|
// Technically unrelated, but important to perform before detection
|
||||||
driver.SetLibvirtURI(viper.GetString(kvmQemuURI))
|
driver.SetLibvirtURI(viper.GetString(kvmQemuURI))
|
||||||
|
@ -770,7 +794,7 @@ func validateUser(drvName string) {
|
||||||
|
|
||||||
out.ErrT(style.Stopped, `The "{{.driver_name}}" driver should not be used with root privileges.`, out.V{"driver_name": drvName})
|
out.ErrT(style.Stopped, `The "{{.driver_name}}" driver should not be used with root privileges.`, out.V{"driver_name": drvName})
|
||||||
out.ErrT(style.Tip, "If you are running minikube within a VM, consider using --driver=none:")
|
out.ErrT(style.Tip, "If you are running minikube within a VM, consider using --driver=none:")
|
||||||
out.ErrT(style.Documentation, " https://minikube.sigs.k8s.io/docs/reference/drivers/none/")
|
out.ErrT(style.Documentation, " {{.url}}", out.V{"url": "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"})
|
||||||
|
|
||||||
cname := ClusterFlagValue()
|
cname := ClusterFlagValue()
|
||||||
_, err = config.Load(cname)
|
_, err = config.Load(cname)
|
||||||
|
@ -805,7 +829,7 @@ func memoryLimits(drvName string) (int, int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, -1, err
|
return -1, -1, err
|
||||||
}
|
}
|
||||||
containerLimit = int(s.TotalMemory / 1024 / 1024)
|
containerLimit = util.ConvertBytesToMB(s.TotalMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sysLimit, containerLimit, nil
|
return sysLimit, containerLimit, nil
|
||||||
|
@ -1185,6 +1209,10 @@ func validateKubernetesVersion(old *config.ClusterConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isBaseImageApplicable(drv string) bool {
|
||||||
|
return registry.IsKIC(drv)
|
||||||
|
}
|
||||||
|
|
||||||
func getKubernetesVersion(old *config.ClusterConfig) string {
|
func getKubernetesVersion(old *config.ClusterConfig) string {
|
||||||
paramVersion := viper.GetString(kubernetesVersion)
|
paramVersion := viper.GetString(kubernetesVersion)
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,10 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
cfg "k8s.io/minikube/pkg/minikube/config"
|
cfg "k8s.io/minikube/pkg/minikube/config"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
|
"k8s.io/minikube/pkg/minikube/driver"
|
||||||
"k8s.io/minikube/pkg/minikube/proxy"
|
"k8s.io/minikube/pkg/minikube/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -278,3 +280,33 @@ func TestSuggestMemoryAllocation(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBaseImageFlagDriverCombo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
driver string
|
||||||
|
canUseBaseImg bool
|
||||||
|
}{
|
||||||
|
{driver.Docker, true},
|
||||||
|
{driver.Podman, true},
|
||||||
|
{driver.None, false},
|
||||||
|
{driver.KVM2, false},
|
||||||
|
{driver.VirtualBox, false},
|
||||||
|
{driver.HyperKit, false},
|
||||||
|
{driver.VMware, false},
|
||||||
|
{driver.VMwareFusion, false},
|
||||||
|
{driver.HyperV, false},
|
||||||
|
{driver.Parallels, false},
|
||||||
|
{"something_invalid", false},
|
||||||
|
{"", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.driver, func(t *testing.T) {
|
||||||
|
got := isBaseImageApplicable(test.driver)
|
||||||
|
if got != test.canUseBaseImg {
|
||||||
|
t.Errorf("isBaseImageApplicable(driver=%v): got %v, expected %v",
|
||||||
|
test.driver, got, test.canUseBaseImg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -60,8 +60,6 @@ func init() {
|
||||||
if err := viper.GetViper().BindPFlags(stopCmd.Flags()); err != nil {
|
if err := viper.GetViper().BindPFlags(stopCmd.Flags()); err != nil {
|
||||||
exit.Error(reason.InternalFlagsBind, "unable to bind flags", err)
|
exit.Error(reason.InternalFlagsBind, "unable to bind flags", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
RootCmd.AddCommand(stopCmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// runStop handles the executes the flow of "minikube stop"
|
// runStop handles the executes the flow of "minikube stop"
|
||||||
|
|
|
@ -45,5 +45,11 @@ var updateContextCmd = &cobra.Command{
|
||||||
} else {
|
} else {
|
||||||
out.T(style.Meh, `No changes required for the "{{.context}}" context`, out.V{"context": cname})
|
out.T(style.Meh, `No changes required for the "{{.context}}" context`, out.V{"context": cname})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := kubeconfig.SetCurrentContext(cname, kubeconfig.PathFromEnv()); err != nil {
|
||||||
|
out.ErrT(style.Sad, `Error while setting kubectl current context: {{.error}}`, out.V{"error": err})
|
||||||
|
} else {
|
||||||
|
out.T(style.Kubectl, `Current context is "{{.context}}"`, out.V{"context": cname})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,9 @@ import (
|
||||||
// Register drivers
|
// Register drivers
|
||||||
_ "k8s.io/minikube/pkg/minikube/registry/drvs"
|
_ "k8s.io/minikube/pkg/minikube/registry/drvs"
|
||||||
|
|
||||||
|
// Force exp dependency
|
||||||
|
_ "golang.org/x/exp/ebnf"
|
||||||
|
|
||||||
mlog "github.com/docker/machine/libmachine/log"
|
mlog "github.com/docker/machine/libmachine/log"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
|
@ -18,12 +18,17 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"k8s.io/minikube/pkg/perf/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
for {
|
for {
|
||||||
|
log.Print("~~~~~~~~~ Starting performance analysis ~~~~~~~~~~~~~~")
|
||||||
if err := analyzePerformance(context.Background()); err != nil {
|
if err := analyzePerformance(context.Background()); err != nil {
|
||||||
log.Printf("error executing performance analysis: %v", err)
|
log.Printf("error executing performance analysis: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -36,5 +41,32 @@ func main() {
|
||||||
// 2. running mkcmp against those PRs
|
// 2. running mkcmp against those PRs
|
||||||
// 3. commenting results on those PRs
|
// 3. commenting results on those PRs
|
||||||
func analyzePerformance(ctx context.Context) error {
|
func analyzePerformance(ctx context.Context) error {
|
||||||
|
client := monitor.NewClient(ctx, monitor.GithubOwner, monitor.GithubRepo)
|
||||||
|
prs, err := client.ListOpenPRsWithLabel(monitor.OkToTestLabel)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "listing open prs")
|
||||||
|
}
|
||||||
|
log.Print("got prs:", prs)
|
||||||
|
for _, pr := range prs {
|
||||||
|
log.Printf("~~~ Analyzing PR %d ~~~", pr)
|
||||||
|
newCommitsExist, err := client.NewCommitsExist(pr, monitor.BotName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !newCommitsExist {
|
||||||
|
log.Println("New commits don't exist, skipping rerun...")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var message string
|
||||||
|
message, err = monitor.RunMkcmp(ctx, pr)
|
||||||
|
if err != nil {
|
||||||
|
message = fmt.Sprintf("Error: %v\n%s", err, message)
|
||||||
|
}
|
||||||
|
log.Printf("message for pr %d:\n%s\n", pr, message)
|
||||||
|
if err := client.CommentOnPR(pr, message); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Print("successfully commented on PR")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,10 +131,17 @@ metadata:
|
||||||
app: gcp-auth
|
app: gcp-auth
|
||||||
webhooks:
|
webhooks:
|
||||||
- name: gcp-auth-mutate.k8s.io
|
- name: gcp-auth-mutate.k8s.io
|
||||||
|
failurePolicy: Fail
|
||||||
objectSelector:
|
objectSelector:
|
||||||
matchExpressions:
|
matchExpressions:
|
||||||
- key: gcp-auth-skip-secret
|
- key: gcp-auth-skip-secret
|
||||||
operator: DoesNotExist
|
operator: DoesNotExist
|
||||||
|
namespaceSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: name
|
||||||
|
operator: NotIn
|
||||||
|
values:
|
||||||
|
- kube-system
|
||||||
sideEffects: None
|
sideEffects: None
|
||||||
admissionReviewVersions: ["v1","v1beta1"]
|
admissionReviewVersions: ["v1","v1beta1"]
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Turn on Source Address Verification in all interfaces to
|
||||||
|
# prevent some spoofing attacks.
|
||||||
|
net.ipv4.conf.default.rp_filter=1
|
||||||
|
net.ipv4.conf.all.rp_filter=1
|
|
@ -1,44 +1,125 @@
|
||||||
|
# Copyright 2018 The Kubernetes Authors.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# kind node base image
|
||||||
|
#
|
||||||
|
# For systemd + docker configuration used below, see the following references:
|
||||||
|
# https://www.freedesktop.org/wiki/Software/systemd/ContainerInterface/
|
||||||
|
|
||||||
|
# start from ubuntu 20.04, this image is reasonably small as a starting point
|
||||||
|
# for a kubernetes node image, it doesn't contain much we don't need
|
||||||
|
FROM ubuntu:focal-20200423
|
||||||
|
|
||||||
|
# copy in static files (configs, scripts)
|
||||||
|
COPY 10-network-security.conf /etc/sysctl.d/10-network-security.conf
|
||||||
|
COPY clean-install /usr/local/bin/clean-install
|
||||||
|
COPY entrypoint /usr/local/bin/entrypoint
|
||||||
|
|
||||||
|
# Install dependencies, first from apt, then from release tarballs.
|
||||||
|
# NOTE: we use one RUN to minimize layers.
|
||||||
|
#
|
||||||
|
# First we must ensure that our util scripts are executable.
|
||||||
|
#
|
||||||
|
# The base image already has: ssh, apt, snapd, but we need to install more packages.
|
||||||
|
# Packages installed are broken down into (each on a line):
|
||||||
|
# - packages needed to run services (systemd)
|
||||||
|
# - packages needed for kubernetes components
|
||||||
|
# - packages needed by the container runtime
|
||||||
|
# - misc packages kind uses itself
|
||||||
|
# After installing packages we cleanup by:
|
||||||
|
# - removing unwanted systemd services
|
||||||
|
# - disabling kmsg in journald (these log entries would be confusing)
|
||||||
|
#
|
||||||
|
# Next we ensure the /etc/kubernetes/manifests directory exists. Normally
|
||||||
|
# a kubeadm debain / rpm package would ensure that this exists but we install
|
||||||
|
# freshly built binaries directly when we build the node image.
|
||||||
|
#
|
||||||
|
# Finally we adjust tempfiles cleanup to be 1 minute after "boot" instead of 15m
|
||||||
|
# This is plenty after we've done initial setup for a node, but before we are
|
||||||
|
# likely to try to export logs etc.
|
||||||
|
RUN echo "Ensuring scripts are executable ..." \
|
||||||
|
&& chmod +x /usr/local/bin/clean-install /usr/local/bin/entrypoint \
|
||||||
|
&& echo "Installing Packages ..." \
|
||||||
|
&& DEBIAN_FRONTEND=noninteractive clean-install \
|
||||||
|
systemd \
|
||||||
|
conntrack iptables iproute2 ethtool socat util-linux mount ebtables udev kmod \
|
||||||
|
libseccomp2 \
|
||||||
|
bash ca-certificates curl rsync \
|
||||||
|
&& find /lib/systemd/system/sysinit.target.wants/ -name "systemd-tmpfiles-setup.service" -delete \
|
||||||
|
&& rm -f /lib/systemd/system/multi-user.target.wants/* \
|
||||||
|
&& rm -f /etc/systemd/system/*.wants/* \
|
||||||
|
&& rm -f /lib/systemd/system/local-fs.target.wants/* \
|
||||||
|
&& rm -f /lib/systemd/system/sockets.target.wants/*udev* \
|
||||||
|
&& rm -f /lib/systemd/system/sockets.target.wants/*initctl* \
|
||||||
|
&& rm -f /lib/systemd/system/basic.target.wants/* \
|
||||||
|
&& echo "ReadKMsg=no" >> /etc/systemd/journald.conf \
|
||||||
|
&& ln -s "$(which systemd)" /sbin/init \
|
||||||
|
&& echo "Ensuring /etc/kubernetes/manifests" \
|
||||||
|
&& mkdir -p /etc/kubernetes/manifests \
|
||||||
|
&& echo "Adjusting systemd-tmpfiles timer" \
|
||||||
|
&& sed -i /usr/lib/systemd/system/systemd-tmpfiles-clean.timer -e 's#OnBootSec=.*#OnBootSec=1min#' \
|
||||||
|
&& echo "Modifying /etc/nsswitch.conf to prefer hosts" \
|
||||||
|
&& sed -i /etc/nsswitch.conf -re 's#^(hosts:\s*).*#\1dns files#'
|
||||||
|
|
||||||
|
# tell systemd that it is in docker (it will check for the container env)
|
||||||
|
# https://www.freedesktop.org/wiki/Software/systemd/ContainerInterface/
|
||||||
|
ENV container docker
|
||||||
|
# systemd exits on SIGRTMIN+3, not SIGTERM (which re-executes it)
|
||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1201657
|
||||||
|
STOPSIGNAL SIGRTMIN+3
|
||||||
|
# NOTE: this is *only* for documentation, the entrypoint is overridden later
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/entrypoint", "/sbin/init" ]
|
||||||
|
|
||||||
ARG COMMIT_SHA
|
ARG COMMIT_SHA
|
||||||
# using base image created by kind https://github.com/kubernetes-sigs/kind/blob/v0.8.1/images/base/Dockerfile
|
# using base image created by kind https://github.com/kubernetes-sigs/kind/blob/2c0eee40/images/base/Dockerfile
|
||||||
# which is an ubuntu 20.04 with an entry-point that helps running systemd
|
# which is an ubuntu 20.04 with an entry-point that helps running systemd
|
||||||
# could be changed to any debian that can run systemd
|
# could be changed to any debian that can run systemd
|
||||||
FROM kindest/base:v20200430-2c0eee40 as base
|
|
||||||
USER root
|
USER root
|
||||||
# specify version of everything explicitly using 'apt-cache policy'
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
# install system requirements from the regular distro repositories
|
||||||
|
RUN clean-install \
|
||||||
lz4 \
|
lz4 \
|
||||||
gnupg \
|
gnupg \
|
||||||
sudo \
|
sudo \
|
||||||
docker.io \
|
docker.io \
|
||||||
|
containerd \
|
||||||
openssh-server \
|
openssh-server \
|
||||||
dnsutils \
|
dnsutils \
|
||||||
runc \
|
runc \
|
||||||
# libglib2.0-0 is required for conmon, which is required for podman
|
# libglib2.0-0 is required for conmon, which is required for podman
|
||||||
libglib2.0-0 \
|
libglib2.0-0
|
||||||
# removing kind's crictl config
|
|
||||||
&& rm /etc/crictl.yaml
|
|
||||||
|
|
||||||
# Install cri-o/podman dependencies:
|
# Install cri-o/podman dependencies:
|
||||||
RUN sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_20.04/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list" && \
|
RUN sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_20.04/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list" && \
|
||||||
curl -LO https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/xUbuntu_20.04/Release.key && \
|
curl -LO https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/xUbuntu_20.04/Release.key && \
|
||||||
apt-key add - < Release.key && apt-get update && \
|
apt-key add - < Release.key && \
|
||||||
apt-get install -y --no-install-recommends containers-common catatonit conmon containernetworking-plugins podman-plugins varlink
|
clean-install containers-common catatonit conmon containernetworking-plugins cri-tools podman-plugins varlink
|
||||||
|
|
||||||
# install cri-o based on https://github.com/cri-o/cri-o/commit/96b0c34b31a9fc181e46d7d8e34fb8ee6c4dc4e1#diff-04c6e90faac2675aa89e2176d2eec7d8R128
|
# install cri-o based on https://github.com/cri-o/cri-o/commit/96b0c34b31a9fc181e46d7d8e34fb8ee6c4dc4e1#diff-04c6e90faac2675aa89e2176d2eec7d8R128
|
||||||
RUN sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.18:/1.18.3/xUbuntu_20.04/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list" && \
|
RUN sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.18:/1.18.3/xUbuntu_20.04/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list" && \
|
||||||
curl -LO https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.18:/1.18.3/xUbuntu_20.04/Release.key && \
|
curl -LO https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/1.18:/1.18.3/xUbuntu_20.04/Release.key && \
|
||||||
apt-key add - < Release.key && apt-get update && \
|
apt-key add - < Release.key && \
|
||||||
apt-get install -y --no-install-recommends cri-o=1.18.3~3
|
clean-install cri-o=1.18.3~3
|
||||||
|
|
||||||
# install podman
|
# install podman
|
||||||
RUN sh -c "echo 'deb https://dl.bintray.com/afbjorklund/podman focal main' > /etc/apt/sources.list.d/podman.list" && \
|
RUN sh -c "echo 'deb https://dl.bintray.com/afbjorklund/podman focal main' > /etc/apt/sources.list.d/podman.list" && \
|
||||||
curl -L https://bintray.com/user/downloadSubjectPublicKey?username=afbjorklund -o afbjorklund-public.key.asc && \
|
curl -L https://bintray.com/user/downloadSubjectPublicKey?username=afbjorklund -o afbjorklund-public.key.asc && \
|
||||||
apt-key add - < afbjorklund-public.key.asc && apt-get update && \
|
apt-key add - < afbjorklund-public.key.asc && \
|
||||||
apt-get install -y --no-install-recommends podman=1.9.3~1
|
clean-install podman=1.9.3~1
|
||||||
|
|
||||||
RUN mkdir -p /usr/lib/cri-o-runc/sbin && cp /usr/local/sbin/runc /usr/lib/cri-o-runc/sbin/runc
|
RUN mkdir -p /usr/lib/cri-o-runc/sbin && cp /usr/sbin/runc /usr/lib/cri-o-runc/sbin/runc
|
||||||
|
|
||||||
COPY entrypoint /usr/local/bin/entrypoint
|
|
||||||
# automount service
|
# automount service
|
||||||
COPY automount/minikube-automount /usr/sbin/minikube-automount
|
COPY automount/minikube-automount /usr/sbin/minikube-automount
|
||||||
COPY automount/minikube-automount.service /usr/lib/systemd/system/minikube-automount.service
|
COPY automount/minikube-automount.service /usr/lib/systemd/system/minikube-automount.service
|
||||||
|
@ -71,12 +152,7 @@ USER root
|
||||||
# https://github.com/kubernetes-sigs/kind/blob/master/images/base/files/usr/local/bin/entrypoint
|
# https://github.com/kubernetes-sigs/kind/blob/master/images/base/files/usr/local/bin/entrypoint
|
||||||
RUN mkdir -p /kind
|
RUN mkdir -p /kind
|
||||||
# Deleting leftovers
|
# Deleting leftovers
|
||||||
RUN apt-get clean -y && rm -rf \
|
RUN rm -rf \
|
||||||
/var/cache/debconf/* \
|
|
||||||
/var/lib/apt/lists/* \
|
|
||||||
/var/log/* \
|
|
||||||
/tmp/* \
|
|
||||||
/var/tmp/* \
|
|
||||||
/usr/share/doc/* \
|
/usr/share/doc/* \
|
||||||
/usr/share/man/* \
|
/usr/share/man/* \
|
||||||
/usr/share/local/* \
|
/usr/share/local/* \
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright 2017 The Kubernetes Authors.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# A script encapsulating a common Dockerimage pattern for installing packages
|
||||||
|
# and then cleaning up the unnecessary install artifacts.
|
||||||
|
# e.g. clean-install iptables ebtables conntrack
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
|
if [ $# = 0 ]; then
|
||||||
|
echo >&2 "No packages specified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends "$@"
|
||||||
|
apt-get clean -y
|
||||||
|
rm -rf \
|
||||||
|
/var/cache/debconf/* \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/var/log/* \
|
||||||
|
/tmp/* \
|
||||||
|
/var/tmp/* \
|
||||||
|
/usr/share/doc/* \
|
||||||
|
/usr/share/man/* \
|
||||||
|
/usr/share/local/*
|
|
@ -1,4 +1,12 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"name": "v1.13.1",
|
||||||
|
"checksums": {
|
||||||
|
"darwin": "cc7eaadea2becc48eee78136f8d569df55a28c46d58d1c8bb434895382aced78",
|
||||||
|
"linux": "3564b685f8d797df78ebfa2f5b34c99b3c77b0d1f49eab6aab37500f1ba61d98",
|
||||||
|
"windows": "0d315ec21ca8a34eff5fa4cc478c09ed2d48ae88b3c5d586df9de111ac414d44"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "v1.13.0",
|
"name": "v1.13.0",
|
||||||
"checksums": {
|
"checksums": {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -28,6 +28,7 @@ require (
|
||||||
github.com/google/go-cmp v0.4.1
|
github.com/google/go-cmp v0.4.1
|
||||||
github.com/google/go-containerregistry v0.0.0-20200601195303-96cf69f03a3c
|
github.com/google/go-containerregistry v0.0.0-20200601195303-96cf69f03a3c
|
||||||
github.com/google/go-github v17.0.0+incompatible
|
github.com/google/go-github v17.0.0+incompatible
|
||||||
|
github.com/google/go-github/v32 v32.1.0
|
||||||
github.com/google/slowjam v0.0.0-20200530021616-df27e642fe7b
|
github.com/google/slowjam v0.0.0-20200530021616-df27e642fe7b
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/googleapis/gnostic v0.3.0 // indirect
|
github.com/googleapis/gnostic v0.3.0 // indirect
|
||||||
|
@ -72,6 +73,7 @@ require (
|
||||||
github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097
|
github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097
|
||||||
golang.org/x/build v0.0.0-20190927031335-2835ba2e683f
|
golang.org/x/build v0.0.0-20190927031335-2835ba2e683f
|
||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121
|
golang.org/x/sys v0.0.0-20200523222454-059865788121
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -517,6 +517,8 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||||
|
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
|
||||||
|
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
||||||
|
@ -1204,6 +1206,7 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
|
|
@ -81,7 +81,7 @@ for path in $(gsutil ls "gs://${ISO_BUCKET}/minikube-v${VERSION}*" || true); do
|
||||||
done
|
done
|
||||||
|
|
||||||
# Upload all end-user assets other than preload files, as they are release independent
|
# Upload all end-user assets other than preload files, as they are release independent
|
||||||
for file in out/minikube[_-]* out/docker-machine-*; do
|
for file in $( find out \( -name "minikube[_-]*" -or -name "docker-machine-*" \) -and ! -name "*latest*"); do
|
||||||
n=0
|
n=0
|
||||||
until [ $n -ge 5 ]
|
until [ $n -ge 5 ]
|
||||||
do
|
do
|
||||||
|
|
|
@ -17,70 +17,156 @@ limitations under the License.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
|
"flag"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v32/github"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) == 1 {
|
// init glog: by default, all log statements write to files in a temporary directory, also
|
||||||
fmt.Println("Usage: go run update_kubernetes_version.go <kubernetes_version>")
|
// flag.Parse must be called before any logging is done
|
||||||
os.Exit(1)
|
flag.Parse()
|
||||||
}
|
_ = flag.Set("logtostderr", "true")
|
||||||
|
|
||||||
v := os.Args[1]
|
// fetch respective current stable (vDefault as DefaultKubernetesVersion) and
|
||||||
if !strings.HasPrefix(v, "v") {
|
// latest rc or beta (vDefault as NewestKubernetesVersion) Kubernetes GitHub Releases
|
||||||
v = "v" + v
|
vDefault, vNewest, err := fetchKubernetesReleases()
|
||||||
}
|
|
||||||
|
|
||||||
constantsFile := "../../pkg/minikube/constants/constants.go"
|
|
||||||
cf, err := ioutil.ReadFile(constantsFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
glog.Errorf("Fetching current GitHub Releases failed: %v", err)
|
||||||
os.Exit(1)
|
}
|
||||||
|
if vDefault == "" || vNewest == "" {
|
||||||
|
glog.Fatalf("Cannot determine current 'DefaultKubernetesVersion' and 'NewestKubernetesVersion'")
|
||||||
|
}
|
||||||
|
glog.Infof("Current Kubernetes GitHub Releases: 'stable' is %s and 'latest' is %s", vDefault, vNewest)
|
||||||
|
|
||||||
|
if err := updateKubernetesVersions(vDefault, vNewest); err != nil {
|
||||||
|
glog.Fatalf("Updating 'DefaultKubernetesVersion' and 'NewestKubernetesVersion' failed: %v", err)
|
||||||
|
}
|
||||||
|
glog.Infof("Update successful: 'DefaultKubernetesVersion' was set to %s and 'NewestKubernetesVersion' was set to %s", vDefault, vNewest)
|
||||||
|
|
||||||
|
// Flush before exiting to guarantee all log output is written
|
||||||
|
glog.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := os.Stat(constantsFile)
|
// fetchKubernetesReleases returns respective current stable (as vDefault) and
|
||||||
|
// latest rc or beta (as vNewest) Kubernetes GitHub Releases, and any error
|
||||||
|
func fetchKubernetesReleases() (vDefault, vNewest string, err error) {
|
||||||
|
client := github.NewClient(nil)
|
||||||
|
|
||||||
|
// set a context with a deadline - timeout after at most 10 seconds
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// walk through the paginated list of all 'kubernetes/kubernetes' repo releases
|
||||||
|
// from latest to older releases, until latest release and pre-release are found
|
||||||
|
// use max value (100) for PerPage to avoid hitting the rate limits (60 per hour, 10 per minute)
|
||||||
|
// see https://godoc.org/github.com/google/go-github/github#hdr-Rate_Limiting
|
||||||
|
opt := &github.ListOptions{PerPage: 100}
|
||||||
|
for {
|
||||||
|
rels, resp, err := client.Repositories.ListReleases(ctx, "kubernetes", "kubernetes", opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
return "", "", err
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
mode := info.Mode()
|
|
||||||
|
|
||||||
re := regexp.MustCompile(`DefaultKubernetesVersion = \".*`)
|
|
||||||
f := re.ReplaceAllString(string(cf), "DefaultKubernetesVersion = \""+v+"\"")
|
|
||||||
|
|
||||||
re = regexp.MustCompile(`NewestKubernetesVersion = \".*`)
|
|
||||||
f = re.ReplaceAllString(f, "NewestKubernetesVersion = \""+v+"\"")
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(constantsFile, []byte(f), mode); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testData := "../../pkg/minikube/bootstrapper/bsutil/testdata"
|
for _, r := range rels {
|
||||||
|
// GetName returns the Name field if it's non-nil, zero value otherwise.
|
||||||
|
ver := r.GetName()
|
||||||
|
if ver == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
err = filepath.Walk(testData, func(path string, info os.FileInfo, err error) error {
|
rel := strings.Split(ver, "-")
|
||||||
|
// check if it is a release channel (ie, 'v1.19.2') or a
|
||||||
|
// pre-release channel (ie, 'v1.19.3-rc.0' or 'v1.19.0-beta.2')
|
||||||
|
if len(rel) == 1 && vDefault == "" {
|
||||||
|
vDefault = ver
|
||||||
|
} else if len(rel) > 1 && vNewest == "" {
|
||||||
|
if strings.HasPrefix(rel[1], "rc") || strings.HasPrefix(rel[1], "beta") {
|
||||||
|
vNewest = ver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if vDefault != "" && vNewest != "" {
|
||||||
|
// make sure that vNewest >= vDefault
|
||||||
|
if vNewest < vDefault {
|
||||||
|
vNewest = vDefault
|
||||||
|
}
|
||||||
|
return vDefault, vNewest, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.NextPage == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
opt.Page = resp.NextPage
|
||||||
|
}
|
||||||
|
return vDefault, vNewest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateKubernetesVersions updates DefaultKubernetesVersion to vDefault release and
|
||||||
|
// NewestKubernetesVersion to vNewest release, and returns any error
|
||||||
|
func updateKubernetesVersions(vDefault, vNewest string) error {
|
||||||
|
if err := replaceAllString("../../pkg/minikube/constants/constants.go", map[string]string{
|
||||||
|
`DefaultKubernetesVersion = \".*`: "DefaultKubernetesVersion = \"" + vDefault + "\"",
|
||||||
|
`NewestKubernetesVersion = \".*`: "NewestKubernetesVersion = \"" + vNewest + "\"",
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := replaceAllString("../../site/content/en/docs/commands/start.md", map[string]string{
|
||||||
|
`'stable' for .*,`: "'stable' for " + vDefault + ",",
|
||||||
|
`'latest' for .*\)`: "'latest' for " + vNewest + ")",
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update testData just for the latest 'v<MAJOR>.<MINOR>.0' from vDefault
|
||||||
|
vDefaultMM := vDefault[:strings.LastIndex(vDefault, ".")]
|
||||||
|
testData := "../../pkg/minikube/bootstrapper/bsutil/testdata/" + vDefaultMM
|
||||||
|
|
||||||
|
return filepath.Walk(testData, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(path, "default.yaml") {
|
if !strings.HasSuffix(path, "default.yaml") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
cf, err = ioutil.ReadFile(path)
|
return replaceAllString(path, map[string]string{
|
||||||
|
`kubernetesVersion: .*`: "kubernetesVersion: " + vDefaultMM + ".0",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// replaceAllString replaces all occuranes of map's keys with their respective values in the file
|
||||||
|
func replaceAllString(path string, pairs map[string]string) error {
|
||||||
|
fb, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
re = regexp.MustCompile(`kubernetesVersion: .*`)
|
|
||||||
cf = []byte(re.ReplaceAllString(string(cf), "kubernetesVersion: "+v))
|
info, err := os.Stat(path)
|
||||||
return ioutil.WriteFile(path, cf, info.Mode())
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Walk failed: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
|
mode := info.Mode()
|
||||||
|
|
||||||
|
f := string(fb)
|
||||||
|
for org, new := range pairs {
|
||||||
|
re := regexp.MustCompile(org)
|
||||||
|
f = re.ReplaceAllString(f, new)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(path, []byte(f), mode); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import (
|
||||||
|
|
||||||
func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string) error {
|
func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string) error {
|
||||||
driver := kic.NewDriver(kic.Config{
|
driver := kic.NewDriver(kic.Config{
|
||||||
|
ClusterName: profile,
|
||||||
KubernetesVersion: kubernetesVersion,
|
KubernetesVersion: kubernetesVersion,
|
||||||
ContainerRuntime: containerRuntime,
|
ContainerRuntime: containerRuntime,
|
||||||
OCIBinary: oci.Docker,
|
OCIBinary: oci.Docker,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<svg width="702px" height="683px" viewBox="0 0 702 683" version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="https://www.w3.org/1999/xlink">
|
<svg width="702px" height="683px" viewBox="0 0 702 683" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 39.1 (31720) - https://www.sketchapp.com/ -->
|
<!-- Generator: Sketch 39.1 (31720) - http://www.bohemiancoding.com/sketch -->
|
||||||
<title>minikube</title>
|
<title>minikube</title>
|
||||||
<desc>Created with Sketch.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<defs>
|
<defs>
|
||||||
|
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
@ -324,7 +324,18 @@ func verifyAddonStatus(cc *config.ClusterConfig, name string, val string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyGCPAuthAddon(cc *config.ClusterConfig, name string, val string) error {
|
func verifyGCPAuthAddon(cc *config.ClusterConfig, name string, val string) error {
|
||||||
return verifyAddonStatusInternal(cc, name, val, "gcp-auth")
|
enable, err := strconv.ParseBool(val)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "parsing bool: %s", name)
|
||||||
|
}
|
||||||
|
err = verifyAddonStatusInternal(cc, name, val, "gcp-auth")
|
||||||
|
|
||||||
|
if enable && err == nil {
|
||||||
|
out.T(style.Notice, "Your GCP credentials will now be mounted into every pod created in the {{.name}} cluster.", out.V{"name": cc.Name})
|
||||||
|
out.T(style.Notice, "If you don't want your credentials mounted into a specific pod, add a label with the `gcp-auth-skip-secret` key to your pod configuration.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyAddonStatusInternal(cc *config.ClusterConfig, name string, val string, ns string) error {
|
func verifyAddonStatusInternal(cc *config.ClusterConfig, name string, val string, ns string) error {
|
||||||
|
@ -394,16 +405,26 @@ func Start(wg *sync.WaitGroup, cc *config.ClusterConfig, toEnable map[string]boo
|
||||||
|
|
||||||
var awg sync.WaitGroup
|
var awg sync.WaitGroup
|
||||||
|
|
||||||
defer func() { // making it show after verifications( not perfect till #7613 is closed)
|
enabledAddons := []string{}
|
||||||
|
deferredAddons := []string{}
|
||||||
|
|
||||||
|
defer func() { // making it show after verifications (see #7613)
|
||||||
register.Reg.SetStep(register.EnablingAddons)
|
register.Reg.SetStep(register.EnablingAddons)
|
||||||
out.T(style.AddonEnable, "Enabled addons: {{.addons}}", out.V{"addons": strings.Join(toEnableList, ", ")})
|
out.T(style.AddonEnable, "Enabled addons: {{.addons}}", out.V{"addons": strings.Join(enabledAddons, ", ")})
|
||||||
}()
|
}()
|
||||||
for _, a := range toEnableList {
|
for _, a := range toEnableList {
|
||||||
|
if a == "gcp-auth" {
|
||||||
|
deferredAddons = append(deferredAddons, a)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
awg.Add(1)
|
awg.Add(1)
|
||||||
go func(name string) {
|
go func(name string) {
|
||||||
err := RunCallbacks(cc, name, "true")
|
err := RunCallbacks(cc, name, "true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out.WarningT("Enabling '{{.name}}' returned an error: {{.error}}", out.V{"name": name, "error": err})
|
out.WarningT("Enabling '{{.name}}' returned an error: {{.error}}", out.V{"name": name, "error": err})
|
||||||
|
} else {
|
||||||
|
enabledAddons = append(enabledAddons, name)
|
||||||
}
|
}
|
||||||
awg.Done()
|
awg.Done()
|
||||||
}(a)
|
}(a)
|
||||||
|
@ -411,7 +432,18 @@ func Start(wg *sync.WaitGroup, cc *config.ClusterConfig, toEnable map[string]boo
|
||||||
|
|
||||||
// Wait until all of the addons are enabled before updating the config (not thread safe)
|
// Wait until all of the addons are enabled before updating the config (not thread safe)
|
||||||
awg.Wait()
|
awg.Wait()
|
||||||
for _, a := range toEnableList {
|
|
||||||
|
// Now run the deferred addons
|
||||||
|
for _, a := range deferredAddons {
|
||||||
|
err := RunCallbacks(cc, a, "true")
|
||||||
|
if err != nil {
|
||||||
|
out.WarningT("Enabling '{{.name}}' returned an error: {{.error}}", out.V{"name": a, "error": err})
|
||||||
|
} else {
|
||||||
|
enabledAddons = append(enabledAddons, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range enabledAddons {
|
||||||
if err := Set(cc, a, "true"); err != nil {
|
if err := Set(cc, a, "true"); err != nil {
|
||||||
glog.Errorf("store failed: %v", err)
|
glog.Errorf("store failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,7 @@ var Addons = []*Addon{
|
||||||
{
|
{
|
||||||
name: "gcp-auth",
|
name: "gcp-auth",
|
||||||
set: SetBool,
|
set: SetBool,
|
||||||
callbacks: []setFn{gcpauth.EnableOrDisable, enableOrDisableAddon, verifyGCPAuthAddon, gcpauth.DisplayAddonMessage},
|
callbacks: []setFn{gcpauth.EnableOrDisable, enableOrDisableAddon, verifyGCPAuthAddon},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "volumesnapshots",
|
name: "volumesnapshots",
|
||||||
|
|
|
@ -60,7 +60,7 @@ func enableAddon(cfg *config.ClusterConfig) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
creds, err := google.FindDefaultCredentials(ctx)
|
creds, err := google.FindDefaultCredentials(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit.Message(reason.InternalCredsNotFound, "Could not find any GCP credentials. Either run `gcloud auth login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.")
|
exit.Message(reason.InternalCredsNotFound, "Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.")
|
||||||
}
|
}
|
||||||
|
|
||||||
f := assets.NewMemoryAssetTarget(creds.JSON, credentialsPath, "0444")
|
f := assets.NewMemoryAssetTarget(creds.JSON, credentialsPath, "0444")
|
||||||
|
@ -116,16 +116,3 @@ func disableAddon(cfg *config.ClusterConfig) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayAddonMessage display an gcp auth addon specific message to the user
|
|
||||||
func DisplayAddonMessage(cfg *config.ClusterConfig, name string, val string) error {
|
|
||||||
enable, err := strconv.ParseBool(val)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "parsing bool: %s", name)
|
|
||||||
}
|
|
||||||
if enable {
|
|
||||||
out.T(style.Notice, "Your GCP credentials will now be mounted into every pod created in the {{.name}} cluster.", out.V{"name": cfg.Name})
|
|
||||||
out.T(style.Notice, "If you don't want your credentials mounted into a specific pod, add a label with the `gcp-auth-skip-secret` key to your pod configuration.")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/docker/machine/libmachine/ssh"
|
"github.com/docker/machine/libmachine/ssh"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"k8s.io/minikube/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file is for common code shared among internal machine drivers
|
// This file is for common code shared among internal machine drivers
|
||||||
|
@ -74,7 +75,7 @@ func createRawDiskImage(sshKeyPath, diskPath string, diskSizeMb int) error {
|
||||||
return errors.Wrapf(err, "closing file %s", diskPath)
|
return errors.Wrapf(err, "closing file %s", diskPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Truncate(diskPath, int64(diskSizeMb*1000000)); err != nil {
|
if err := os.Truncate(diskPath, util.ConvertMBToBytes(diskSizeMb)); err != nil {
|
||||||
return errors.Wrap(err, "truncate")
|
return errors.Wrap(err, "truncate")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -36,7 +36,7 @@ func Test_createDiskImage(t *testing.T) {
|
||||||
diskPath := filepath.Join(tmpdir, "disk")
|
diskPath := filepath.Join(tmpdir, "disk")
|
||||||
|
|
||||||
sizeInMb := 100
|
sizeInMb := 100
|
||||||
sizeInBytes := int64(sizeInMb) * 1000000
|
sizeInBytes := int64(104857600)
|
||||||
if err := createRawDiskImage(sshPath, diskPath, sizeInMb); err != nil {
|
if err := createRawDiskImage(sshPath, diskPath, sizeInMb); err != nil {
|
||||||
t.Errorf("createDiskImage() error = %v", err)
|
t.Errorf("createDiskImage() error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
"k8s.io/minikube/pkg/minikube/cruntime"
|
"k8s.io/minikube/pkg/minikube/cruntime"
|
||||||
"k8s.io/minikube/pkg/minikube/download"
|
"k8s.io/minikube/pkg/minikube/download"
|
||||||
|
"k8s.io/minikube/pkg/minikube/driver"
|
||||||
|
"k8s.io/minikube/pkg/minikube/out"
|
||||||
"k8s.io/minikube/pkg/minikube/sysinit"
|
"k8s.io/minikube/pkg/minikube/sysinit"
|
||||||
"k8s.io/minikube/pkg/util/retry"
|
"k8s.io/minikube/pkg/util/retry"
|
||||||
)
|
)
|
||||||
|
@ -81,6 +83,17 @@ func (d *Driver) Create() error {
|
||||||
APIServerPort: d.NodeConfig.APIServerPort,
|
APIServerPort: d.NodeConfig.APIServerPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if gateway, err := oci.CreateNetwork(d.OCIBinary, d.NodeConfig.ClusterName); err != nil {
|
||||||
|
out.WarningT("Unable to create dedicated network, this might result in cluster IP change after restart: {{.error}}", out.V{"error": err})
|
||||||
|
} else {
|
||||||
|
params.Network = d.NodeConfig.ClusterName
|
||||||
|
ip := gateway.To4()
|
||||||
|
// calculate the container IP based on guessing the machine index
|
||||||
|
ip[3] += byte(driver.IndexFromMachineName(d.NodeConfig.MachineName))
|
||||||
|
glog.Infof("calculated static IP %q for the %q container", ip.String(), d.NodeConfig.MachineName)
|
||||||
|
params.IP = ip.String()
|
||||||
|
}
|
||||||
|
|
||||||
// control plane specific options
|
// control plane specific options
|
||||||
params.PortMappings = append(params.PortMappings, oci.PortMapping{
|
params.PortMappings = append(params.PortMappings, oci.PortMapping{
|
||||||
ListenAddress: oci.DefaultBindIPV4,
|
ListenAddress: oci.DefaultBindIPV4,
|
||||||
|
@ -289,6 +302,10 @@ func (d *Driver) Remove() error {
|
||||||
if id, err := oci.ContainerID(d.OCIBinary, d.MachineName); err == nil && id != "" {
|
if id, err := oci.ContainerID(d.OCIBinary, d.MachineName); err == nil && id != "" {
|
||||||
return fmt.Errorf("expected no container ID be found for %q after delete. but got %q", d.MachineName, id)
|
return fmt.Errorf("expected no container ID be found for %q after delete. but got %q", d.MachineName, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := oci.RemoveNetwork(d.NodeConfig.ClusterName); err != nil {
|
||||||
|
glog.Warningf("failed to remove network (which might be okay) %s: %v", d.NodeConfig.ClusterName, err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +420,7 @@ func killAPIServerProc(runner command.Runner) error {
|
||||||
pid, err := strconv.Atoi(rr.Stdout.String())
|
pid, err := strconv.Atoi(rr.Stdout.String())
|
||||||
if err == nil { // this means we have a valid pid
|
if err == nil { // this means we have a valid pid
|
||||||
glog.Warningf("Found a kube-apiserver running with pid %d, will try to kill the proc", pid)
|
glog.Warningf("Found a kube-apiserver running with pid %d, will try to kill the proc", pid)
|
||||||
if _, err = runner.RunCmd(exec.Command("pkill", "-9", string(pid))); err != nil {
|
if _, err = runner.RunCmd(exec.Command("pkill", "-9", fmt.Sprint(pid))); err != nil {
|
||||||
return errors.Wrap(err, "kill")
|
return errors.Wrap(err, "kill")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,9 +144,11 @@ func runCmd(cmd *exec.Cmd, warnSlow ...bool) (*RunResult, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if exitError, ok := err.(*exec.ExitError); ok {
|
if ex, ok := err.(*exec.ExitError); ok {
|
||||||
rr.ExitCode = exitError.ExitCode()
|
glog.Warningf("%s returned with exit code %d", rr.Command(), ex.ExitCode())
|
||||||
|
rr.ExitCode = ex.ExitCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrease log spam
|
// Decrease log spam
|
||||||
if elapsed > (1 * time.Second) {
|
if elapsed > (1 * time.Second) {
|
||||||
glog.Infof("Completed: %s: (%s)", rr.Command(), elapsed)
|
glog.Infof("Completed: %s: (%s)", rr.Command(), elapsed)
|
||||||
|
|
|
@ -39,12 +39,27 @@ var ErrWindowsContainers = &FailFastError{errors.New("docker container type is w
|
||||||
// ErrCPUCountLimit is thrown when docker daemon doesn't have enough CPUs for the requested container
|
// ErrCPUCountLimit is thrown when docker daemon doesn't have enough CPUs for the requested container
|
||||||
var ErrCPUCountLimit = &FailFastError{errors.New("not enough CPUs is available for container")}
|
var ErrCPUCountLimit = &FailFastError{errors.New("not enough CPUs is available for container")}
|
||||||
|
|
||||||
|
// ErrIPinUse is thrown when the container been given an IP used by another container
|
||||||
|
var ErrIPinUse = &FailFastError{errors.New("can't create with that IP, address already in use")}
|
||||||
|
|
||||||
// ErrExitedUnexpectedly is thrown when container is created/started without error but later it exists and it's status is not running anymore.
|
// ErrExitedUnexpectedly is thrown when container is created/started without error but later it exists and it's status is not running anymore.
|
||||||
var ErrExitedUnexpectedly = errors.New("container exited unexpectedly")
|
var ErrExitedUnexpectedly = errors.New("container exited unexpectedly")
|
||||||
|
|
||||||
// ErrDaemonInfo is thrown when docker/podman info is failing or not responding
|
// ErrDaemonInfo is thrown when docker/podman info is failing or not responding
|
||||||
var ErrDaemonInfo = errors.New("daemon info not responding")
|
var ErrDaemonInfo = errors.New("daemon info not responding")
|
||||||
|
|
||||||
|
// ErrNetworkSubnetTaken is thrown when a subnet is taken by another network
|
||||||
|
var ErrNetworkSubnetTaken = errors.New("subnet is taken")
|
||||||
|
|
||||||
|
// ErrNetworkNotFound is when given network was not found
|
||||||
|
var ErrNetworkNotFound = errors.New("kic network not found")
|
||||||
|
|
||||||
|
// ErrNetworkGatewayTaken is when given network gatway is taken
|
||||||
|
var ErrNetworkGatewayTaken = errors.New("network gateway is taken")
|
||||||
|
|
||||||
|
// ErrNetworkInUse is when trying to delete a network which is attached to another container
|
||||||
|
var ErrNetworkInUse = errors.New("unable to delete a network that is attached to a running container")
|
||||||
|
|
||||||
// LogContainerDebug will print relevant docker/podman infos after a container fails
|
// LogContainerDebug will print relevant docker/podman infos after a container fails
|
||||||
func LogContainerDebug(ociBin string, name string) string {
|
func LogContainerDebug(ociBin string, name string) string {
|
||||||
rr, err := containerInspect(ociBin, name)
|
rr, err := containerInspect(ociBin, name)
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,10 +33,13 @@ type SysInfo struct {
|
||||||
OSType string // container's OsType (windows or linux)
|
OSType string // container's OsType (windows or linux)
|
||||||
Swarm bool // Weather or not the docker swarm is active
|
Swarm bool // Weather or not the docker swarm is active
|
||||||
StorageDriver string // the storage driver for the daemon (for example overlay2)
|
StorageDriver string // the storage driver for the daemon (for example overlay2)
|
||||||
|
Errors []string // any server issues
|
||||||
}
|
}
|
||||||
|
|
||||||
var cachedSysInfo *SysInfo
|
var (
|
||||||
var cachedSysInfoErr *error
|
cachedSysInfo *SysInfo
|
||||||
|
cachedSysInfoErr *error
|
||||||
|
)
|
||||||
|
|
||||||
// CachedDaemonInfo will run and return a docker/podman info only once per minikube run time. to avoid performance
|
// CachedDaemonInfo will run and return a docker/podman info only once per minikube run time. to avoid performance
|
||||||
func CachedDaemonInfo(ociBin string) (SysInfo, error) {
|
func CachedDaemonInfo(ociBin string) (SysInfo, error) {
|
||||||
|
@ -58,7 +62,7 @@ func DaemonInfo(ociBin string) (SysInfo, error) {
|
||||||
return *cachedSysInfo, err
|
return *cachedSysInfo, err
|
||||||
}
|
}
|
||||||
d, err := dockerSystemInfo()
|
d, err := dockerSystemInfo()
|
||||||
cachedSysInfo = &SysInfo{CPUs: d.NCPU, TotalMemory: d.MemTotal, OSType: d.OSType, Swarm: d.Swarm.LocalNodeState == "active", StorageDriver: d.Driver}
|
cachedSysInfo = &SysInfo{CPUs: d.NCPU, TotalMemory: d.MemTotal, OSType: d.OSType, Swarm: d.Swarm.LocalNodeState == "active", StorageDriver: d.Driver, Errors: d.ServerErrors}
|
||||||
return *cachedSysInfo, err
|
return *cachedSysInfo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +167,7 @@ type dockerSysInfo struct {
|
||||||
SecurityOptions []string `json:"SecurityOptions"`
|
SecurityOptions []string `json:"SecurityOptions"`
|
||||||
ProductLicense string `json:"ProductLicense"`
|
ProductLicense string `json:"ProductLicense"`
|
||||||
Warnings interface{} `json:"Warnings"`
|
Warnings interface{} `json:"Warnings"`
|
||||||
|
ServerErrors []string
|
||||||
ClientInfo struct {
|
ClientInfo struct {
|
||||||
Debug bool `json:"Debug"`
|
Debug bool `json:"Debug"`
|
||||||
Plugins []interface{} `json:"Plugins"`
|
Plugins []interface{} `json:"Plugins"`
|
||||||
|
@ -245,6 +250,7 @@ func dockerSystemInfo() (dockerSysInfo, error) {
|
||||||
return ds, errors.Wrapf(err, "unmarshal docker system info")
|
return ds, errors.Wrapf(err, "unmarshal docker system info")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glog.Infof("docker info: %+v", ds)
|
||||||
return ds, nil
|
return ds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,5 +270,6 @@ func podmanSystemInfo() (podmanSysInfo, error) {
|
||||||
if err := json.Unmarshal([]byte(strings.TrimSpace(rawJSON)), &ps); err != nil {
|
if err := json.Unmarshal([]byte(strings.TrimSpace(rawJSON)), &ps); err != nil {
|
||||||
return ps, errors.Wrapf(err, "unmarshal podman system info")
|
return ps, errors.Wrapf(err, "unmarshal podman system info")
|
||||||
}
|
}
|
||||||
|
glog.Infof("podman info: %+v", ps)
|
||||||
return ps, nil
|
return ps, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,17 +31,26 @@ import (
|
||||||
|
|
||||||
// RoutableHostIPFromInside returns the ip/dns of the host that container lives on
|
// RoutableHostIPFromInside returns the ip/dns of the host that container lives on
|
||||||
// is routable from inside the container
|
// is routable from inside the container
|
||||||
func RoutableHostIPFromInside(ociBin string, containerName string) (net.IP, error) {
|
func RoutableHostIPFromInside(ociBin string, clusterName string, containerName string) (net.IP, error) {
|
||||||
if ociBin == Docker {
|
if ociBin == Docker {
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
return dockerGatewayIP(containerName)
|
_, gateway, err := dockerNetworkInspect(clusterName)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, ErrNetworkNotFound) {
|
||||||
|
glog.Infof("The container %s is not attached to a network, this could be because the cluster was created by minikube <v1.14, will try to get the IP using container gatway", containerName)
|
||||||
|
|
||||||
|
return containerGatewayIP(Docker, containerName)
|
||||||
|
}
|
||||||
|
return gateway, errors.Wrap(err, "network inspect")
|
||||||
|
}
|
||||||
|
return gateway, nil
|
||||||
}
|
}
|
||||||
// for windows and mac, the gateway ip is not routable so we use dns trick.
|
// for windows and mac, the gateway ip is not routable so we use dns trick.
|
||||||
return digDNS(ociBin, containerName, "host.docker.internal")
|
return digDNS(ociBin, containerName, "host.docker.internal")
|
||||||
}
|
}
|
||||||
|
// podman
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
return containerGatewayIP(ociBin, containerName)
|
return containerGatewayIP(Podman, containerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("RoutableHostIPFromInside is currently only implemented for linux")
|
return nil, fmt.Errorf("RoutableHostIPFromInside is currently only implemented for linux")
|
||||||
|
@ -59,56 +68,8 @@ func digDNS(ociBin, containerName, dns string) (net.IP, error) {
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// profileInContainers checks whether the profile is within the containers list
|
|
||||||
func profileInContainers(profile string, containers []string) bool {
|
|
||||||
for _, container := range containers {
|
|
||||||
if container == profile {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// dockerGatewayIP gets the default gateway ip for the docker bridge on the user's host machine
|
|
||||||
// gets the ip from user's host docker
|
|
||||||
func dockerGatewayIP(profile string) (net.IP, error) {
|
|
||||||
var bridgeID string
|
|
||||||
rr, err := runCmd(exec.Command(Docker, "network", "ls", "--filter", "name=bridge", "--format", "{{.ID}}"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "get network bridge")
|
|
||||||
}
|
|
||||||
networksOutput := strings.TrimSpace(rr.Stdout.String())
|
|
||||||
networksSlice := strings.Fields(networksOutput)
|
|
||||||
// Look for the minikube container within each docker network
|
|
||||||
for _, net := range networksSlice {
|
|
||||||
// get all containers in the network
|
|
||||||
rs, err := runCmd(exec.Command(Docker, "network", "inspect", net, "-f", "{{range $k, $v := .Containers}}{{$v.Name}} {{end}}"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "get containers in network")
|
|
||||||
}
|
|
||||||
containersSlice := strings.Fields(rs.Stdout.String())
|
|
||||||
if profileInContainers(profile, containersSlice) {
|
|
||||||
bridgeID = net
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if bridgeID == "" {
|
|
||||||
return nil, errors.Errorf("unable to determine bridge network id from %q", networksOutput)
|
|
||||||
}
|
|
||||||
rr, err = runCmd(exec.Command(Docker, "network", "inspect",
|
|
||||||
"--format", "{{(index .IPAM.Config 0).Gateway}}", bridgeID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "inspect IP bridge network %q.", bridgeID)
|
|
||||||
}
|
|
||||||
|
|
||||||
ip := net.ParseIP(strings.TrimSpace(rr.Stdout.String()))
|
|
||||||
glog.Infof("got host ip for mount in container by inspect docker network: %s", ip.String())
|
|
||||||
return ip, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// containerGatewayIP gets the default gateway ip for the container
|
// containerGatewayIP gets the default gateway ip for the container
|
||||||
func containerGatewayIP(ociBin, containerName string) (net.IP, error) {
|
func containerGatewayIP(ociBin string, containerName string) (net.IP, error) {
|
||||||
rr, err := runCmd(exec.Command(ociBin, "container", "inspect", "--format", "{{.NetworkSettings.Gateway}}", containerName))
|
rr, err := runCmd(exec.Command(ociBin, "container", "inspect", "--format", "{{.NetworkSettings.Gateway}}", containerName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "inspect gateway")
|
return nil, errors.Wrapf(err, "inspect gateway")
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 oci
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// firstSubnetAddr subnet to be used on first kic cluster
|
||||||
|
// it is one octet more than the one used by KVM to avoid possible conflict
|
||||||
|
const firstSubnetAddr = "192.168.49.0"
|
||||||
|
|
||||||
|
// big enough for a cluster of 254 nodes
|
||||||
|
const defaultSubnetMask = 24
|
||||||
|
|
||||||
|
// CreateNetwork creates a network returns gateway and error, minikube creates one network per cluster
|
||||||
|
func CreateNetwork(ociBin string, name string) (net.IP, error) {
|
||||||
|
if ociBin != Docker {
|
||||||
|
return nil, fmt.Errorf("%s network not implemented yet", ociBin)
|
||||||
|
}
|
||||||
|
return createDockerNetwork(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDockerNetwork(clusterName string) (net.IP, error) {
|
||||||
|
// check if the network already exists
|
||||||
|
subnet, gateway, err := dockerNetworkInspect(clusterName)
|
||||||
|
if err == nil {
|
||||||
|
glog.Infof("Found existing network with subnet %s and gateway %s.", subnet, gateway)
|
||||||
|
return gateway, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
attempts := 0
|
||||||
|
subnetAddr := firstSubnetAddr
|
||||||
|
// Rather than iterate through all of the valid subnets, give up at 20 to avoid a lengthy user delay for something that is unlikely to work.
|
||||||
|
// will be like 192.168.49.0/24 ,...,192.168.239.0/24
|
||||||
|
for attempts < 20 {
|
||||||
|
gateway, err = tryCreateDockerNetwork(subnetAddr, defaultSubnetMask, clusterName)
|
||||||
|
if err == nil {
|
||||||
|
return gateway, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't retry if error is not adddress is taken
|
||||||
|
if !(errors.Is(err, ErrNetworkSubnetTaken) || errors.Is(err, ErrNetworkGatewayTaken)) {
|
||||||
|
glog.Errorf("error while trying to create network %v", err)
|
||||||
|
return nil, errors.Wrap(err, "un-retryable")
|
||||||
|
}
|
||||||
|
attempts++
|
||||||
|
// Find an open subnet by incrementing the 3rd octet by 10 for each try
|
||||||
|
// 13 times adding 10 firstSubnetAddr "192.168.49.0/24"
|
||||||
|
// at most it will add up to 169 which is still less than max allowed 255
|
||||||
|
// this is large enough to try more and not too small to not try enough
|
||||||
|
// can be tuned in the next iterations
|
||||||
|
newSubnet := net.ParseIP(subnetAddr).To4()
|
||||||
|
newSubnet[2] += byte(9 + attempts)
|
||||||
|
subnetAddr = newSubnet.String()
|
||||||
|
}
|
||||||
|
return gateway, fmt.Errorf("failed to create network after 20 attempts")
|
||||||
|
}
|
||||||
|
|
||||||
|
func tryCreateDockerNetwork(subnetAddr string, subnetMask int, name string) (net.IP, error) {
|
||||||
|
gateway := net.ParseIP(subnetAddr)
|
||||||
|
gateway.To4()[3]++ // first ip for gateway
|
||||||
|
glog.Infof("attempt to create network %s/%d with subnet: %s and gateway %s...", subnetAddr, subnetMask, name, gateway)
|
||||||
|
// options documentation https://docs.docker.com/engine/reference/commandline/network_create/#bridge-driver-options
|
||||||
|
rr, err := runCmd(exec.Command(Docker, "network", "create", "--driver=bridge", fmt.Sprintf("--subnet=%s", fmt.Sprintf("%s/%d", subnetAddr, subnetMask)), fmt.Sprintf("--gateway=%s", gateway), "-o", "--ip-masq", "-o", "--icc", fmt.Sprintf("--label=%s=%s", CreatedByLabelKey, "true"), name))
|
||||||
|
if err != nil {
|
||||||
|
// Pool overlaps with other one on this address space
|
||||||
|
if strings.Contains(rr.Output(), "Pool overlaps") {
|
||||||
|
return nil, ErrNetworkSubnetTaken
|
||||||
|
}
|
||||||
|
if strings.Contains(rr.Output(), "failed to allocate gateway") && strings.Contains(rr.Output(), "Address already in use") {
|
||||||
|
return nil, ErrNetworkGatewayTaken
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(err, "create network %s", fmt.Sprintf("%s %s/%d", name, subnetAddr, subnetMask))
|
||||||
|
}
|
||||||
|
return gateway, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns subnet and gate if exists
|
||||||
|
func dockerNetworkInspect(name string) (*net.IPNet, net.IP, error) {
|
||||||
|
rr, err := runCmd(exec.Command(Docker, "network", "inspect", name, "--format", "{{(index .IPAM.Config 0).Subnet}},{{(index .IPAM.Config 0).Gateway}}"))
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(rr.Output(), "No such network") {
|
||||||
|
return nil, nil, ErrNetworkNotFound
|
||||||
|
}
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// results looks like 172.17.0.0/16,172.17.0.1
|
||||||
|
ips := strings.Split(strings.TrimSpace(rr.Stdout.String()), ",")
|
||||||
|
if len(ips) == 0 {
|
||||||
|
return nil, nil, fmt.Errorf("empty IP list parsed from: %q", rr.Output())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, subnet, err := net.ParseCIDR(ips[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrapf(err, "parse subnet for %s", name)
|
||||||
|
}
|
||||||
|
var gateway net.IP
|
||||||
|
if len(ips) > 0 {
|
||||||
|
gateway = net.ParseIP(ips[1])
|
||||||
|
}
|
||||||
|
return subnet, gateway, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveNetwork removes a network
|
||||||
|
func RemoveNetwork(name string) error {
|
||||||
|
if !networkExists(name) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rr, err := runCmd(exec.Command(Docker, "network", "remove", name))
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(rr.Output(), "No such network") {
|
||||||
|
return ErrNetworkNotFound
|
||||||
|
}
|
||||||
|
// Error response from daemon: error while removing network: network mynet123 id f9e1c50b89feb0b8f4b687f3501a81b618252c9907bc20666e386d0928322387 has active endpoints
|
||||||
|
if strings.Contains(rr.Output(), "has active endpoints") {
|
||||||
|
return ErrNetworkInUse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func networkExists(name string) bool {
|
||||||
|
_, _, err := dockerNetworkInspect(name)
|
||||||
|
if err != nil && !errors.Is(err, ErrNetworkNotFound) { // log unexpected error
|
||||||
|
glog.Warningf("Error inspecting docker network %s: %v", name, err)
|
||||||
|
}
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// networkNamesByLabel returns all network names created by a label
|
||||||
|
func networkNamesByLabel(ociBin string, label string) ([]string, error) {
|
||||||
|
if ociBin != Docker {
|
||||||
|
return nil, fmt.Errorf("%s not supported", ociBin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// docker network ls --filter='label=created_by.minikube.sigs.k8s.io=true' --format '{{.Name}}'
|
||||||
|
rr, err := runCmd(exec.Command(Docker, "network", "ls", fmt.Sprintf("--filter=label=%s", label), "--format", "{{.Name}}"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var lines []string
|
||||||
|
scanner := bufio.NewScanner(bytes.NewReader(rr.Stdout.Bytes()))
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, strings.TrimSpace(scanner.Text()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteKICNetworks deletes all networks created by kic
|
||||||
|
func DeleteKICNetworks() []error {
|
||||||
|
var errs []error
|
||||||
|
ns, err := networkNamesByLabel(Docker, CreatedByLabelKey+"=true")
|
||||||
|
if err != nil {
|
||||||
|
return []error{errors.Wrap(err, "list all volume")}
|
||||||
|
}
|
||||||
|
for _, n := range ns {
|
||||||
|
err := RemoveNetwork(n)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -169,6 +169,11 @@ func CreateContainerNode(p CreateParams) error {
|
||||||
virtualization = "podman" // VIRTUALIZATION_PODMAN
|
virtualization = "podman" // VIRTUALIZATION_PODMAN
|
||||||
}
|
}
|
||||||
if p.OCIBinary == Docker {
|
if p.OCIBinary == Docker {
|
||||||
|
// to provide a static IP for docker
|
||||||
|
if p.Network != "" && p.IP != "" {
|
||||||
|
runArgs = append(runArgs, "--network", p.Network)
|
||||||
|
runArgs = append(runArgs, "--ip", p.IP)
|
||||||
|
}
|
||||||
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var", p.Name))
|
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var", p.Name))
|
||||||
// ignore apparmore github actions docker: https://github.com/kubernetes/minikube/issues/7624
|
// ignore apparmore github actions docker: https://github.com/kubernetes/minikube/issues/7624
|
||||||
runArgs = append(runArgs, "--security-opt", "apparmor=unconfined")
|
runArgs = append(runArgs, "--security-opt", "apparmor=unconfined")
|
||||||
|
@ -285,6 +290,10 @@ func createContainer(ociBin string, image string, opts ...createOpt) error {
|
||||||
if strings.Contains(rr.Output(), "Range of CPUs is from") && strings.Contains(rr.Output(), "CPUs available") { // CPUs available
|
if strings.Contains(rr.Output(), "Range of CPUs is from") && strings.Contains(rr.Output(), "CPUs available") { // CPUs available
|
||||||
return ErrCPUCountLimit
|
return ErrCPUCountLimit
|
||||||
}
|
}
|
||||||
|
// example: docker: Error response from daemon: Address already in use.
|
||||||
|
if strings.Contains(rr.Output(), "Address already in use") {
|
||||||
|
return ErrIPinUse
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ const (
|
||||||
|
|
||||||
// CreateParams are parameters needed to create a container
|
// CreateParams are parameters needed to create a container
|
||||||
type CreateParams struct {
|
type CreateParams struct {
|
||||||
|
ClusterName string // cluster(profile name) that this container belongs to
|
||||||
Name string // used for container name and hostname
|
Name string // used for container name and hostname
|
||||||
Image string // container image to use to create the node.
|
Image string // container image to use to create the node.
|
||||||
ClusterLabel string // label the clusters we create using minikube so we can clean up
|
ClusterLabel string // label the clusters we create using minikube so we can clean up
|
||||||
|
@ -56,6 +57,8 @@ type CreateParams struct {
|
||||||
Envs map[string]string // environment variables to pass to the container
|
Envs map[string]string // environment variables to pass to the container
|
||||||
ExtraArgs []string // a list of any extra option to pass to oci binary during creation time, for example --expose 8080...
|
ExtraArgs []string // a list of any extra option to pass to oci binary during creation time, for example --expose 8080...
|
||||||
OCIBinary string // docker or podman
|
OCIBinary string // docker or podman
|
||||||
|
Network string // network name that the container will attach to
|
||||||
|
IP string // static IP to assign for th container in the cluster network
|
||||||
}
|
}
|
||||||
|
|
||||||
// createOpt is an option for Create
|
// createOpt is an option for Create
|
||||||
|
|
|
@ -24,9 +24,9 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Version is the current version of kic
|
// Version is the current version of kic
|
||||||
Version = "v0.0.12-snapshot3"
|
Version = "v0.0.13-snapshot1"
|
||||||
// SHA of the kic base image
|
// SHA of the kic base image
|
||||||
baseImageSHA = "1d687ba53e19dbe5fafe4cc18aa07f269ecc4b7b622f2251b5bf569ddb474e9b"
|
baseImageSHA = "4d43acbd0050148d4bc399931f1b15253b5e73815b63a67b8ab4a5c9e523403f"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -48,6 +48,7 @@ var (
|
||||||
|
|
||||||
// Config is configuration for the kic driver used by registry
|
// Config is configuration for the kic driver used by registry
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
ClusterName string // The cluster the container belongs to
|
||||||
MachineName string // maps to the container name being created
|
MachineName string // maps to the container name being created
|
||||||
CPU int // Number of CPU cores assigned to the container
|
CPU int // Number of CPU cores assigned to the container
|
||||||
Memory int // max memory in MB
|
Memory int // max memory in MB
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
const domainTmpl = `
|
const domainTmpl = `
|
||||||
<domain type='kvm'>
|
<domain type='kvm'>
|
||||||
<name>{{.MachineName}}</name>
|
<name>{{.MachineName}}</name>
|
||||||
<memory unit='MB'>{{.Memory}}</memory>
|
<memory unit='MiB'>{{.Memory}}</memory>
|
||||||
<vcpu>{{.CPU}}</vcpu>
|
<vcpu>{{.CPU}}</vcpu>
|
||||||
<features>
|
<features>
|
||||||
<acpi/>
|
<acpi/>
|
||||||
|
|
|
@ -34,12 +34,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// HostIP gets the ip address to be used for mapping host -> VM and VM -> host
|
// HostIP gets the ip address to be used for mapping host -> VM and VM -> host
|
||||||
func HostIP(host *host.Host) (net.IP, error) {
|
func HostIP(host *host.Host, clusterName string) (net.IP, error) {
|
||||||
switch host.DriverName {
|
switch host.DriverName {
|
||||||
case driver.Docker:
|
case driver.Docker:
|
||||||
return oci.RoutableHostIPFromInside(oci.Docker, host.Name)
|
return oci.RoutableHostIPFromInside(oci.Docker, clusterName, host.Name)
|
||||||
case driver.Podman:
|
case driver.Podman:
|
||||||
return oci.RoutableHostIPFromInside(oci.Podman, host.Name)
|
return oci.RoutableHostIPFromInside(oci.Podman, clusterName, host.Name)
|
||||||
case driver.KVM2:
|
case driver.KVM2:
|
||||||
return net.ParseIP("192.168.39.1"), nil
|
return net.ParseIP("192.168.39.1"), nil
|
||||||
case driver.HyperV:
|
case driver.HyperV:
|
||||||
|
@ -49,6 +49,7 @@ func HostIP(host *host.Host) (net.IP, error) {
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
if v.Type().Field(i).Name == "VSwitch" {
|
if v.Type().Field(i).Name == "VSwitch" {
|
||||||
hypervVirtualSwitch = v.Field(i).Interface().(string)
|
hypervVirtualSwitch = v.Field(i).Interface().(string)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +60,7 @@ func HostIP(host *host.Host) (net.IP, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, errors.Wrap(err, fmt.Sprintf("ip for interface (%s)", hypervVirtualSwitch))
|
return []byte{}, errors.Wrap(err, fmt.Sprintf("ip for interface (%s)", hypervVirtualSwitch))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ip, nil
|
return ip, nil
|
||||||
case driver.VirtualBox:
|
case driver.VirtualBox:
|
||||||
vBoxManageCmd := driver.VBoxManagePath()
|
vBoxManageCmd := driver.VBoxManagePath()
|
||||||
|
@ -74,6 +76,7 @@ func HostIP(host *host.Host) (net.IP, error) {
|
||||||
}
|
}
|
||||||
re = regexp.MustCompile(`(?sm)Name:\s*` + iface + `\s*$.+?IPAddress:\s*(\S+)`)
|
re = regexp.MustCompile(`(?sm)Name:\s*` + iface + `\s*$.+?IPAddress:\s*(\S+)`)
|
||||||
ip := re.FindStringSubmatch(string(ipList))[1]
|
ip := re.FindStringSubmatch(string(ipList))[1]
|
||||||
|
|
||||||
return net.ParseIP(ip), nil
|
return net.ParseIP(ip), nil
|
||||||
case driver.Parallels:
|
case driver.Parallels:
|
||||||
bin := "prlsrvctl"
|
bin := "prlsrvctl"
|
||||||
|
@ -93,6 +96,7 @@ func HostIP(host *host.Host) (net.IP, error) {
|
||||||
return []byte{}, errors.Wrap(err, "Error getting the IP address of Parallels Shared network interface")
|
return []byte{}, errors.Wrap(err, "Error getting the IP address of Parallels Shared network interface")
|
||||||
}
|
}
|
||||||
ip := ipMatch[1]
|
ip := ipMatch[1]
|
||||||
|
|
||||||
return net.ParseIP(ip), nil
|
return net.ParseIP(ip), nil
|
||||||
case driver.HyperKit:
|
case driver.HyperKit:
|
||||||
return net.ParseIP("192.168.64.1"), nil
|
return net.ParseIP("192.168.64.1"), nil
|
||||||
|
@ -136,6 +140,7 @@ func DriverIP(api libmachine.API, machineName string) (net.IP, error) {
|
||||||
|
|
||||||
// Based on code from http://stackoverflow.com/questions/23529663/how-to-get-all-addresses-and-masks-from-local-interfaces-in-go
|
// Based on code from http://stackoverflow.com/questions/23529663/how-to-get-all-addresses-and-masks-from-local-interfaces-in-go
|
||||||
func getIPForInterface(name string) (net.IP, error) {
|
func getIPForInterface(name string) (net.IP, error) {
|
||||||
|
glog.Infof("getIPForInterface: searching for %q", name)
|
||||||
ints, err := net.Interfaces()
|
ints, err := net.Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -143,19 +148,25 @@ func getIPForInterface(name string) (net.IP, error) {
|
||||||
|
|
||||||
var i net.Interface
|
var i net.Interface
|
||||||
for _, in := range ints {
|
for _, in := range ints {
|
||||||
if strings.HasPrefix(in.Name, name) {
|
if strings.HasPrefix(strings.ToLower(in.Name), strings.ToLower(name)) {
|
||||||
|
glog.Infof("found prefix matching interface for %q: %q", name, in.Name)
|
||||||
i = in
|
i = in
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
glog.Infof("%q does not match prefix %q", in.Name, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Didn't find prefix, let's try any substring
|
// Didn't find prefix, let's try any substring
|
||||||
if i.Name == "" {
|
if i.Name == "" {
|
||||||
for _, in := range ints {
|
for _, in := range ints {
|
||||||
if strings.Contains(in.Name, name) {
|
if strings.Contains(strings.ToLower(in.Name), strings.ToLower(name)) {
|
||||||
|
glog.Infof("found substring matching interface for %q: %q", name, in.Name)
|
||||||
i = in
|
i = in
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
glog.Infof("%q does not match substring %q", in.Name, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,14 +175,15 @@ func getIPForInterface(name string) (net.IP, error) {
|
||||||
return nil, errors.Errorf("Could not find interface %s inside %+v", name, ints)
|
return nil, errors.Errorf("Could not find interface %s inside %+v", name, ints)
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Infof("Found hyperv interface: %+v\n", i)
|
glog.Infof("Found interface: %+v\n", i)
|
||||||
addrs, _ := i.Addrs()
|
addrs, _ := i.Addrs()
|
||||||
for _, a := range addrs {
|
for _, a := range addrs {
|
||||||
|
glog.Infof("interface addr: %+v", a)
|
||||||
if ipnet, ok := a.(*net.IPNet); ok {
|
if ipnet, ok := a.(*net.IPNet); ok {
|
||||||
if ip := ipnet.IP.To4(); ip != nil {
|
if ip := ipnet.IP.To4(); ip != nil {
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errors.Errorf("Error finding IPV4 address for %s", name)
|
return nil, errors.Errorf("Unable to find a IPv4 address for interface %q", name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,24 @@ func IsNotExist(err error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrPermissionDenied is the error returned when the config cannot be read
|
||||||
|
// due to insufficient permissions
|
||||||
|
type ErrPermissionDenied struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrPermissionDenied) Error() string {
|
||||||
|
return e.s
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPermissionDenied returns whether the error is a ErrPermissionDenied instance
|
||||||
|
func IsPermissionDenied(err error) bool {
|
||||||
|
if _, ok := err.(*ErrPermissionDenied); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// MinikubeConfig represents minikube config
|
// MinikubeConfig represents minikube config
|
||||||
type MinikubeConfig map[string]interface{}
|
type MinikubeConfig map[string]interface{}
|
||||||
|
|
||||||
|
@ -184,6 +202,9 @@ func (c *simpleConfigLoader) LoadConfigFromFile(profileName string, miniHome ...
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if os.IsPermission(err) {
|
||||||
|
return nil, &ErrPermissionDenied{err.Error()}
|
||||||
|
}
|
||||||
return nil, errors.Wrap(err, "read")
|
return nil, errors.Wrap(err, "read")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
@ -297,3 +298,15 @@ func MachineName(cc config.ClusterConfig, n config.Node) string {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s-%s", cc.Name, n.Name)
|
return fmt.Sprintf("%s-%s", cc.Name, n.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexFromMachineName returns the order of the container based on it is name
|
||||||
|
func IndexFromMachineName(machineName string) int {
|
||||||
|
// minikube-m02
|
||||||
|
sp := strings.Split(machineName, "-")
|
||||||
|
m := strings.Trim(sp[len(sp)-1], "m") // m02
|
||||||
|
i, err := strconv.Atoi(m)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
"k8s.io/minikube/pkg/minikube/registry"
|
"k8s.io/minikube/pkg/minikube/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -201,3 +202,160 @@ func TestSuggest(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMachineName(t *testing.T) {
|
||||||
|
testsCases := []struct {
|
||||||
|
ClusterConfig config.ClusterConfig
|
||||||
|
Want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
ClusterConfig: config.ClusterConfig{Name: "minikube",
|
||||||
|
Nodes: []config.Node{
|
||||||
|
config.Node{
|
||||||
|
Name: "",
|
||||||
|
IP: "172.17.0.3",
|
||||||
|
Port: 8443,
|
||||||
|
KubernetesVersion: "v1.19.2",
|
||||||
|
ControlPlane: true,
|
||||||
|
Worker: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Want: "minikube",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ClusterConfig: config.ClusterConfig{Name: "p2",
|
||||||
|
Nodes: []config.Node{
|
||||||
|
config.Node{
|
||||||
|
Name: "",
|
||||||
|
IP: "172.17.0.3",
|
||||||
|
Port: 8443,
|
||||||
|
KubernetesVersion: "v1.19.2",
|
||||||
|
ControlPlane: true,
|
||||||
|
Worker: true,
|
||||||
|
},
|
||||||
|
config.Node{
|
||||||
|
Name: "m2",
|
||||||
|
IP: "172.17.0.4",
|
||||||
|
Port: 0,
|
||||||
|
KubernetesVersion: "v1.19.2",
|
||||||
|
ControlPlane: false,
|
||||||
|
Worker: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Want: "p2-m2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testsCases {
|
||||||
|
got := MachineName(tc.ClusterConfig, tc.ClusterConfig.Nodes[len(tc.ClusterConfig.Nodes)-1])
|
||||||
|
if got != tc.Want {
|
||||||
|
t.Errorf("Expected MachineName to be %q but got %q", tc.Want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexFromMachineName(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
Name string
|
||||||
|
MachineName string
|
||||||
|
Want int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "default",
|
||||||
|
MachineName: "minikube",
|
||||||
|
Want: 1},
|
||||||
|
{
|
||||||
|
Name: "second-node",
|
||||||
|
MachineName: "minikube-m02",
|
||||||
|
Want: 2},
|
||||||
|
{
|
||||||
|
Name: "funny",
|
||||||
|
MachineName: "hahaha",
|
||||||
|
Want: 1},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "dash-profile",
|
||||||
|
MachineName: "my-dashy-minikube",
|
||||||
|
Want: 1},
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "dash-profile-second-node",
|
||||||
|
MachineName: "my-dashy-minikube-m02",
|
||||||
|
Want: 2},
|
||||||
|
{
|
||||||
|
Name: "michivious-user",
|
||||||
|
MachineName: "michivious-user-m02-m03",
|
||||||
|
Want: 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
got := IndexFromMachineName(tc.MachineName)
|
||||||
|
if got != tc.Want {
|
||||||
|
t.Errorf("want order %q but got %q", tc.Want, got)
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test indexFroMachine against cluster config
|
||||||
|
func TestIndexFromMachineNameClusterConfig(t *testing.T) {
|
||||||
|
|
||||||
|
testsCases := []struct {
|
||||||
|
ClusterConfig config.ClusterConfig
|
||||||
|
Want int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
ClusterConfig: config.ClusterConfig{Name: "minikube",
|
||||||
|
Nodes: []config.Node{
|
||||||
|
config.Node{
|
||||||
|
Name: "",
|
||||||
|
IP: "172.17.0.3",
|
||||||
|
Port: 8443,
|
||||||
|
KubernetesVersion: "v1.19.2",
|
||||||
|
ControlPlane: true,
|
||||||
|
Worker: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Want: 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
ClusterConfig: config.ClusterConfig{Name: "p2",
|
||||||
|
Nodes: []config.Node{
|
||||||
|
config.Node{
|
||||||
|
Name: "",
|
||||||
|
IP: "172.17.0.3",
|
||||||
|
Port: 8443,
|
||||||
|
KubernetesVersion: "v1.19.2",
|
||||||
|
ControlPlane: true,
|
||||||
|
Worker: true,
|
||||||
|
},
|
||||||
|
config.Node{
|
||||||
|
Name: "m2",
|
||||||
|
IP: "172.17.0.4",
|
||||||
|
Port: 0,
|
||||||
|
KubernetesVersion: "v1.19.2",
|
||||||
|
ControlPlane: false,
|
||||||
|
Worker: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Want: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testsCases {
|
||||||
|
got := IndexFromMachineName(MachineName(tc.ClusterConfig, tc.ClusterConfig.Nodes[len(tc.ClusterConfig.Nodes)-1]))
|
||||||
|
if got != tc.Want {
|
||||||
|
t.Errorf("expected IndexFromMachineName to be %d but got %d", tc.Want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import (
|
||||||
var exclude = []string{
|
var exclude = []string{
|
||||||
"{{.error}}",
|
"{{.error}}",
|
||||||
"{{.url}}",
|
"{{.url}}",
|
||||||
|
" {{.url}}",
|
||||||
"{{.msg}}: {{.err}}",
|
"{{.msg}}: {{.err}}",
|
||||||
"{{.key}}={{.value}}",
|
"{{.key}}={{.value}}",
|
||||||
"opt {{.docker_option}}",
|
"opt {{.docker_option}}",
|
||||||
|
@ -50,6 +51,7 @@ var exclude = []string{
|
||||||
"\\n",
|
"\\n",
|
||||||
"==\u003e {{.name}} \u003c==",
|
"==\u003e {{.name}} \u003c==",
|
||||||
"- {{.profile}}",
|
"- {{.profile}}",
|
||||||
|
" - {{.profile}}",
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrMapFile is a constant to refer to the err_map file, which contains the Advice strings.
|
// ErrMapFile is a constant to refer to the err_map file, which contains the Advice strings.
|
||||||
|
@ -333,9 +335,6 @@ func checkString(s string) string {
|
||||||
// Parse out quote marks
|
// Parse out quote marks
|
||||||
stringToTranslate := s[1 : len(s)-1]
|
stringToTranslate := s[1 : len(s)-1]
|
||||||
|
|
||||||
// Trim whitespace
|
|
||||||
stringToTranslate = strings.TrimSpace(stringToTranslate)
|
|
||||||
|
|
||||||
// Don't translate integers
|
// Don't translate integers
|
||||||
if _, err := strconv.Atoi(stringToTranslate); err == nil {
|
if _, err := strconv.Atoi(stringToTranslate); err == nil {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -40,27 +40,27 @@ func MaybeDisplayAdvice(err error, driver string) {
|
||||||
if errors.Is(err, oci.ErrExitedUnexpectedly) || errors.Is(err, oci.ErrDaemonInfo) {
|
if errors.Is(err, oci.ErrExitedUnexpectedly) || errors.Is(err, oci.ErrDaemonInfo) {
|
||||||
out.T(style.Tip, "If you are still interested to make {{.driver_name}} driver work. The following suggestions might help you get passed this issue:", out.V{"driver_name": driver})
|
out.T(style.Tip, "If you are still interested to make {{.driver_name}} driver work. The following suggestions might help you get passed this issue:", out.V{"driver_name": driver})
|
||||||
if driver == oci.Docker || driver == oci.Podman {
|
if driver == oci.Docker || driver == oci.Podman {
|
||||||
out.T(style.Empty, `
|
out.String("\n\t")
|
||||||
- Prune unused {{.driver_name}} images, volumes, networks and abandoned containers.
|
out.T(style.Empty, `- Prune unused {{.driver_name}} images, volumes, networks and abandoned containers.
|
||||||
|
|
||||||
{{.driver_name}} system prune --volumes`, out.V{"driver_name": driver})
|
{{.driver_name}} system prune --volumes`, out.V{"driver_name": driver})
|
||||||
}
|
}
|
||||||
out.T(style.Empty, `
|
out.String("\n\t")
|
||||||
- Restart your {{.driver_name}} service`, out.V{"driver_name": driver})
|
out.T(style.Empty, `- Restart your {{.driver_name}} service`, out.V{"driver_name": driver})
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
out.T(style.Empty, `
|
out.String("\n\t")
|
||||||
- Ensure your {{.driver_name}} daemon has access to enough CPU/memory resources. `, out.V{"driver_name": driver})
|
out.T(style.Empty, `- Ensure your {{.driver_name}} daemon has access to enough CPU/memory resources.`, out.V{"driver_name": driver})
|
||||||
if runtime.GOOS == "darwin" && driver == oci.Docker {
|
if runtime.GOOS == "darwin" && driver == oci.Docker {
|
||||||
out.T(style.Empty, `
|
out.String("\n\t")
|
||||||
- Docs https://docs.docker.com/docker-for-mac/#resources`, out.V{"driver_name": driver})
|
out.T(style.Empty, `- Docs https://docs.docker.com/docker-for-mac/#resources`, out.V{"driver_name": driver})
|
||||||
}
|
}
|
||||||
if runtime.GOOS == "windows" && driver == oci.Docker {
|
if runtime.GOOS == "windows" && driver == oci.Docker {
|
||||||
out.T(style.Empty, `
|
out.String("\n\t")
|
||||||
- Docs https://docs.docker.com/docker-for-windows/#resources`, out.V{"driver_name": driver})
|
out.T(style.Empty, `- Docs https://docs.docker.com/docker-for-windows/#resources`, out.V{"driver_name": driver})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.T(style.Empty, `
|
out.String("\n\t")
|
||||||
- Delete and recreate minikube cluster
|
out.T(style.Empty, `- Delete and recreate minikube cluster
|
||||||
minikube delete
|
minikube delete
|
||||||
minikube start --driver={{.driver_name}}`, out.V{"driver_name": driver})
|
minikube start --driver={{.driver_name}}`, out.V{"driver_name": driver})
|
||||||
// TODO #8348: maybe advice user if to set the --force-systemd https://github.com/kubernetes/minikube/issues/8348
|
// TODO #8348: maybe advice user if to set the --force-systemd https://github.com/kubernetes/minikube/issues/8348
|
||||||
|
|
|
@ -46,7 +46,7 @@ func deleteOrphanedKIC(ociBin string, name string) {
|
||||||
glog.Infof("couldn't inspect container %q before deleting: %v", name, err)
|
glog.Infof("couldn't inspect container %q before deleting: %v", name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// allow no more than 5 seconds for delting the container
|
// allow no more than 5 seconds for deleting the container
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/out"
|
"k8s.io/minikube/pkg/minikube/out"
|
||||||
"k8s.io/minikube/pkg/minikube/out/register"
|
"k8s.io/minikube/pkg/minikube/out/register"
|
||||||
"k8s.io/minikube/pkg/minikube/style"
|
"k8s.io/minikube/pkg/minikube/style"
|
||||||
|
"k8s.io/minikube/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HostInfo holds information on the user's machine
|
// HostInfo holds information on the user's machine
|
||||||
|
@ -38,10 +39,6 @@ type HostInfo struct {
|
||||||
DiskSize int64
|
DiskSize int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func megs(bytes uint64) int64 {
|
|
||||||
return int64(bytes / 1024 / 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CachedHostInfo returns system information such as memory,CPU, DiskSize
|
// CachedHostInfo returns system information such as memory,CPU, DiskSize
|
||||||
func CachedHostInfo() (*HostInfo, error, error, error) {
|
func CachedHostInfo() (*HostInfo, error, error, error) {
|
||||||
var cpuErr, memErr, diskErr error
|
var cpuErr, memErr, diskErr error
|
||||||
|
@ -61,8 +58,8 @@ func CachedHostInfo() (*HostInfo, error, error, error) {
|
||||||
|
|
||||||
var info HostInfo
|
var info HostInfo
|
||||||
info.CPUs = len(i)
|
info.CPUs = len(i)
|
||||||
info.Memory = megs(v.Total)
|
info.Memory = util.ConvertUnsignedBytesToMB(v.Total)
|
||||||
info.DiskSize = megs(d.Total)
|
info.DiskSize = util.ConvertUnsignedBytesToMB(d.Total)
|
||||||
return &info, cpuErr, memErr, diskErr
|
return &info, cpuErr, memErr, diskErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ func beginDownloadKicBaseImage(g *errgroup.Group, cc *config.ClusterConfig, down
|
||||||
// If we end up using a fallback image, notify the user
|
// If we end up using a fallback image, notify the user
|
||||||
defer func() {
|
defer func() {
|
||||||
if finalImg != "" && finalImg != baseImg {
|
if finalImg != "" && finalImg != baseImg {
|
||||||
out.WarningT(fmt.Sprintf("minikube was unable to download %s, but successfully downloaded %s as a fallback image", image.Tag(cc.KicBaseImage), image.Tag(finalImg)))
|
out.WarningT(fmt.Sprintf("minikube was unable to download %s, but successfully downloaded %s as a fallback image", image.Tag(baseImg), image.Tag(finalImg)))
|
||||||
cc.KicBaseImage = finalImg
|
cc.KicBaseImage = finalImg
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -136,7 +136,7 @@ func beginDownloadKicBaseImage(g *errgroup.Group, cc *config.ClusterConfig, down
|
||||||
glog.Infof("successfully loaded %s from cached tarball", img)
|
glog.Infof("successfully loaded %s from cached tarball", img)
|
||||||
// strip the digest from the img before saving it in the config
|
// strip the digest from the img before saving it in the config
|
||||||
// because loading an image from tarball to daemon doesn't load the digest
|
// because loading an image from tarball to daemon doesn't load the digest
|
||||||
finalImg = image.Tag(img)
|
finalImg = img
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
glog.Infof("Downloading %s to local daemon", img)
|
glog.Infof("Downloading %s to local daemon", img)
|
||||||
|
|
|
@ -94,7 +94,7 @@ func Start(starter Starter, apiServer bool) (*kubeconfig.Settings, error) {
|
||||||
showVersionInfo(starter.Node.KubernetesVersion, cr)
|
showVersionInfo(starter.Node.KubernetesVersion, cr)
|
||||||
|
|
||||||
// Add "host.minikube.internal" DNS alias (intentionally non-fatal)
|
// Add "host.minikube.internal" DNS alias (intentionally non-fatal)
|
||||||
hostIP, err := cluster.HostIP(starter.Host)
|
hostIP, err := cluster.HostIP(starter.Host, starter.Cfg.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Unable to get host IP: %v", err)
|
glog.Errorf("Unable to get host IP: %v", err)
|
||||||
} else if err := machine.AddHostAlias(starter.Runner, constants.HostAlias, hostIP); err != nil {
|
} else if err := machine.AddHostAlias(starter.Runner, constants.HostAlias, hostIP); err != nil {
|
||||||
|
@ -311,7 +311,7 @@ func setupKubeAdm(mAPI libmachine.API, cfg config.ClusterConfig, n config.Node,
|
||||||
func setupKubeconfig(h *host.Host, cc *config.ClusterConfig, n *config.Node, clusterName string) *kubeconfig.Settings {
|
func setupKubeconfig(h *host.Host, cc *config.ClusterConfig, n *config.Node, clusterName string) *kubeconfig.Settings {
|
||||||
addr, err := apiServerURL(*h, *cc, *n)
|
addr, err := apiServerURL(*h, *cc, *n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit.Error(reason.DrvCPEndpoint, "Failed to get API Server URL", err)
|
exit.Message(reason.DrvCPEndpoint, fmt.Sprintf("failed to get API Server URL: %v", err), out.V{"profileArg": fmt.Sprintf("--profile=%s", clusterName)})
|
||||||
}
|
}
|
||||||
|
|
||||||
if cc.KubernetesConfig.APIServerName != constants.APIServerName {
|
if cc.KubernetesConfig.APIServerName != constants.APIServerName {
|
||||||
|
|
|
@ -62,7 +62,7 @@ func init() {
|
||||||
Reg = Register{
|
Reg = Register{
|
||||||
// Expected step orders, organized by the initial step seen
|
// Expected step orders, organized by the initial step seen
|
||||||
steps: map[RegStep][]RegStep{
|
steps: map[RegStep][]RegStep{
|
||||||
InitialSetup: []RegStep{
|
InitialSetup: {
|
||||||
InitialSetup,
|
InitialSetup,
|
||||||
SelectingDriver,
|
SelectingDriver,
|
||||||
DownloadingArtifacts,
|
DownloadingArtifacts,
|
||||||
|
@ -78,10 +78,10 @@ func init() {
|
||||||
Done,
|
Done,
|
||||||
},
|
},
|
||||||
|
|
||||||
Stopping: []RegStep{Stopping, Done},
|
Stopping: {Stopping, Done},
|
||||||
Pausing: []RegStep{Pausing, Done},
|
Pausing: {Pausing, Done},
|
||||||
Unpausing: []RegStep{Unpausing, Done},
|
Unpausing: {Unpausing, Done},
|
||||||
Deleting: []RegStep{Deleting, Stopping, Deleting, Done},
|
Deleting: {Deleting, Stopping, Deleting, Done},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,8 @@ func TestTimeCommandLogs(t *testing.T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected log %s but didn't find it", log)
|
t.Fatalf("expected log %s but didn't find it", log)
|
||||||
}
|
}
|
||||||
if actualTime < time {
|
// Let's give a little wiggle room so we don't fail if time is 3 and actualTime is 2.999
|
||||||
|
if actualTime < time && time-actualTime > 0.001 {
|
||||||
t.Fatalf("expected log \"%s\" to take more time than it actually did. got %v, expected > %v", log, actualTime, time)
|
t.Fatalf("expected log \"%s\" to take more time than it actually did. got %v, expected > %v", log, actualTime, time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,12 +202,7 @@ var hostIssues = []match{
|
||||||
GOOS: []string{"linux"},
|
GOOS: []string{"linux"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Kind: Kind{
|
Kind: HostHomePermission,
|
||||||
ID: "HOST_HOME_PERMISSION",
|
|
||||||
ExitCode: ExGuestPermission,
|
|
||||||
Advice: "Your user lacks permissions to the minikube profile directory. Run: 'sudo chown -R $USER $HOME/.minikube; chmod -R u+wrx $HOME/.minikube' to fix",
|
|
||||||
Issues: []int{9165},
|
|
||||||
},
|
|
||||||
Regexp: re(`/.minikube/.*: permission denied`),
|
Regexp: re(`/.minikube/.*: permission denied`),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,13 @@ var (
|
||||||
HostHomeChown = Kind{ID: "HOST_HOME_CHOWN", ExitCode: ExHostPermission}
|
HostHomeChown = Kind{ID: "HOST_HOME_CHOWN", ExitCode: ExHostPermission}
|
||||||
HostBrowser = Kind{ID: "HOST_BROWSER", ExitCode: ExHostError}
|
HostBrowser = Kind{ID: "HOST_BROWSER", ExitCode: ExHostError}
|
||||||
HostConfigLoad = Kind{ID: "HOST_CONFIG_LOAD", ExitCode: ExHostConfig}
|
HostConfigLoad = Kind{ID: "HOST_CONFIG_LOAD", ExitCode: ExHostConfig}
|
||||||
|
HostHomePermission = Kind{
|
||||||
|
ID: "HOST_HOME_PERMISSION",
|
||||||
|
ExitCode: ExHostPermission,
|
||||||
|
Advice: "Your user lacks permissions to the minikube profile directory. Run: 'sudo chown -R $USER $HOME/.minikube; chmod -R u+wrx $HOME/.minikube' to fix",
|
||||||
|
Issues: []int{9165},
|
||||||
|
}
|
||||||
|
|
||||||
HostCurrentUser = Kind{ID: "HOST_CURRENT_USER", ExitCode: ExHostConfig}
|
HostCurrentUser = Kind{ID: "HOST_CURRENT_USER", ExitCode: ExHostConfig}
|
||||||
HostDelCache = Kind{ID: "HOST_DEL_CACHE", ExitCode: ExHostError}
|
HostDelCache = Kind{ID: "HOST_DEL_CACHE", ExitCode: ExHostError}
|
||||||
HostKillMountProc = Kind{ID: "HOST_KILL_MOUNT_PROC", ExitCode: ExHostError}
|
HostKillMountProc = Kind{ID: "HOST_KILL_MOUNT_PROC", ExitCode: ExHostError}
|
||||||
|
@ -207,7 +214,13 @@ var (
|
||||||
ProviderNotFound = Kind{ID: "PROVIDER_NOT_FOUND", ExitCode: ExProviderNotFound}
|
ProviderNotFound = Kind{ID: "PROVIDER_NOT_FOUND", ExitCode: ExProviderNotFound}
|
||||||
ProviderUnavailable = Kind{ID: "PROVIDER_UNAVAILABLE", ExitCode: ExProviderNotFound, Style: style.Shrug}
|
ProviderUnavailable = Kind{ID: "PROVIDER_UNAVAILABLE", ExitCode: ExProviderNotFound, Style: style.Shrug}
|
||||||
|
|
||||||
DrvCPEndpoint = Kind{ID: "DRV_CP_ENDPOINT", ExitCode: ExDriverError}
|
DrvCPEndpoint = Kind{ID: "DRV_CP_ENDPOINT",
|
||||||
|
Advice: `Recreate the cluster by running:
|
||||||
|
minikube delete {{.profileArg}}
|
||||||
|
minikube start {{.profileArg}}`,
|
||||||
|
ExitCode: ExDriverError,
|
||||||
|
Style: style.Failure,
|
||||||
|
}
|
||||||
DrvPortForward = Kind{ID: "DRV_PORT_FORWARD", ExitCode: ExDriverError}
|
DrvPortForward = Kind{ID: "DRV_PORT_FORWARD", ExitCode: ExDriverError}
|
||||||
DrvUnsupportedMulti = Kind{ID: "DRV_UNSUPPORTED_MULTINODE", ExitCode: ExDriverConflict}
|
DrvUnsupportedMulti = Kind{ID: "DRV_UNSUPPORTED_MULTINODE", ExitCode: ExDriverConflict}
|
||||||
DrvUnsupportedOS = Kind{ID: "DRV_UNSUPPORTED_OS", ExitCode: ExDriverUnsupported}
|
DrvUnsupportedOS = Kind{ID: "DRV_UNSUPPORTED_OS", ExitCode: ExDriverUnsupported}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine/drivers"
|
"github.com/docker/machine/libmachine/drivers"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"k8s.io/minikube/pkg/drivers/kic"
|
"k8s.io/minikube/pkg/drivers/kic"
|
||||||
"k8s.io/minikube/pkg/drivers/kic/oci"
|
"k8s.io/minikube/pkg/drivers/kic/oci"
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
|
@ -60,6 +61,7 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return kic.NewDriver(kic.Config{
|
return kic.NewDriver(kic.Config{
|
||||||
|
ClusterName: cc.Name,
|
||||||
MachineName: driver.MachineName(cc, n),
|
MachineName: driver.MachineName(cc, n),
|
||||||
StorePath: localpath.MiniPath(),
|
StorePath: localpath.MiniPath(),
|
||||||
ImageDigest: cc.KicBaseImage,
|
ImageDigest: cc.KicBaseImage,
|
||||||
|
@ -86,34 +88,41 @@ func status() registry.State {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Quickly returns an error code if server is not running
|
|
||||||
cmd := exec.CommandContext(ctx, oci.Docker, "version", "--format", "{{.Server.Os}}-{{.Server.Version}}")
|
cmd := exec.CommandContext(ctx, oci.Docker, "version", "--format", "{{.Server.Os}}-{{.Server.Version}}")
|
||||||
o, err := cmd.Output()
|
o, err := cmd.Output()
|
||||||
output := string(o)
|
if err != nil {
|
||||||
if strings.Contains(output, "windows-") {
|
|
||||||
return registry.State{Error: oci.ErrWindowsContainers, Installed: true, Healthy: false, Fix: "Change container type to \"linux\" in Docker Desktop settings", Doc: docURL + "#verify-docker-container-type-is-linux"}
|
|
||||||
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
glog.Infof("docker version: %s", output)
|
|
||||||
return checkNeedsImprovement()
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.Warningf("docker returned error: %v", err)
|
|
||||||
|
|
||||||
// Basic timeout
|
|
||||||
if ctx.Err() == context.DeadlineExceeded {
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
glog.Warningf("%q timed out. ", strings.Join(cmd.Args, " "))
|
err = errors.Wrapf(err, "deadline exceeded running %q", strings.Join(cmd.Args, " "))
|
||||||
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Restart the Docker service", Doc: docURL}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glog.Warningf("docker version returned error: %v", err)
|
||||||
|
|
||||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||||
stderr := strings.TrimSpace(string(exitErr.Stderr))
|
stderr := strings.TrimSpace(string(exitErr.Stderr))
|
||||||
newErr := fmt.Errorf(`%q %v: %s`, strings.Join(cmd.Args, " "), exitErr, stderr)
|
newErr := fmt.Errorf(`%q %v: %s`, strings.Join(cmd.Args, " "), exitErr, stderr)
|
||||||
|
|
||||||
return suggestFix(stderr, newErr)
|
return suggestFix(stderr, newErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return registry.State{Error: err, Installed: true, Healthy: false, Doc: docURL}
|
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Restart the Docker service", Doc: docURL}
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Infof("docker version: %s", o)
|
||||||
|
if strings.Contains(string(o), "windows-") {
|
||||||
|
return registry.State{Error: oci.ErrWindowsContainers, Installed: true, Healthy: false, Fix: "Change container type to \"linux\" in Docker Desktop settings", Doc: docURL + "#verify-docker-container-type-is-linux"}
|
||||||
|
}
|
||||||
|
|
||||||
|
si, err := oci.CachedDaemonInfo("docker")
|
||||||
|
if err != nil {
|
||||||
|
// No known fix because we haven't yet seen a failure here
|
||||||
|
return registry.State{Error: errors.Wrap(err, "docker info"), Installed: true, Healthy: false, Doc: docURL}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, serr := range si.Errors {
|
||||||
|
return suggestFix(serr, fmt.Errorf("docker info error: %s", serr))
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkNeedsImprovement()
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkNeedsImprovement if overlay mod is installed on a system
|
// checkNeedsImprovement if overlay mod is installed on a system
|
||||||
|
@ -121,6 +130,7 @@ func checkNeedsImprovement() registry.State {
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
return checkOverlayMod()
|
return checkOverlayMod()
|
||||||
}
|
}
|
||||||
|
|
||||||
return registry.State{Installed: true, Healthy: true}
|
return registry.State{Installed: true, Healthy: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,15 +138,18 @@ func checkNeedsImprovement() registry.State {
|
||||||
func checkOverlayMod() registry.State {
|
func checkOverlayMod() registry.State {
|
||||||
if _, err := os.Stat("/sys/module/overlay"); err == nil {
|
if _, err := os.Stat("/sys/module/overlay"); err == nil {
|
||||||
glog.Info("overlay module found")
|
glog.Info("overlay module found")
|
||||||
|
|
||||||
return registry.State{Installed: true, Healthy: true}
|
return registry.State{Installed: true, Healthy: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := os.Stat("/sys/module/overlay2"); err == nil {
|
if _, err := os.Stat("/sys/module/overlay2"); err == nil {
|
||||||
glog.Info("overlay2 module found")
|
glog.Info("overlay2 module found")
|
||||||
|
|
||||||
return registry.State{Installed: true, Healthy: true}
|
return registry.State{Installed: true, Healthy: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Warningf("overlay modules were not found")
|
glog.Warningf("overlay modules were not found")
|
||||||
|
|
||||||
return registry.State{NeedsImprovement: true, Installed: true, Healthy: true, Fix: "enable the overlay Linux kernel module using 'modprobe overlay'"}
|
return registry.State{NeedsImprovement: true, Installed: true, Healthy: true, Fix: "enable the overlay Linux kernel module using 'modprobe overlay'"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,10 +163,14 @@ func suggestFix(stderr string, err error) registry.State {
|
||||||
return registry.State{Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service. If Docker is already running, you may need to reset Docker to factory settings with: Settings > Reset.", Doc: "https://github.com/docker/for-win/issues/1825#issuecomment-450501157"}
|
return registry.State{Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service. If Docker is already running, you may need to reset Docker to factory settings with: Settings > Reset.", Doc: "https://github.com/docker/for-win/issues/1825#issuecomment-450501157"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(stderr, "Cannot connect") || strings.Contains(stderr, "refused") || strings.Contains(stderr, "Is the docker daemon running") || strings.Contains(stderr, "docker daemon is not running") {
|
if dockerNotRunning(stderr) {
|
||||||
return registry.State{Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service", Doc: docURL}
|
return registry.State{Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service", Doc: docURL}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have good advice, but at least we can provide a good error message
|
// We don't have good advice, but at least we can provide a good error message
|
||||||
return registry.State{Error: err, Installed: true, Running: true, Healthy: false, Doc: docURL}
|
return registry.State{Error: err, Installed: true, Running: true, Healthy: false, Doc: docURL}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dockerNotRunning(s string) bool {
|
||||||
|
return strings.Contains(s, "Cannot connect") || strings.Contains(s, "refused") || strings.Contains(s, "Is the docker daemon running") || strings.Contains(s, "docker daemon is not running")
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return kic.NewDriver(kic.Config{
|
return kic.NewDriver(kic.Config{
|
||||||
|
ClusterName: cc.Name,
|
||||||
MachineName: driver.MachineName(cc, n),
|
MachineName: driver.MachineName(cc, n),
|
||||||
StorePath: localpath.MiniPath(),
|
StorePath: localpath.MiniPath(),
|
||||||
ImageDigest: strings.Split(cc.KicBaseImage, "@")[0], // for podman does not support docker images references with both a tag and digest.
|
ImageDigest: strings.Split(cc.KicBaseImage, "@")[0], // for podman does not support docker images references with both a tag and digest.
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 monitor
|
||||||
|
|
||||||
|
const (
|
||||||
|
GithubAccessTokenEnvVar = "GITHUB_ACCESS_TOKEN"
|
||||||
|
OkToTestLabel = "ok-to-test"
|
||||||
|
GithubOwner = "kubernetes"
|
||||||
|
GithubRepo = "minikube"
|
||||||
|
BotName = "minikube-pr-bot"
|
||||||
|
)
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 monitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunMkcmp runs minikube built at the given pr against minikube at master
|
||||||
|
func RunMkcmp(ctx context.Context, pr int) (string, error) {
|
||||||
|
// run 'git pull' so that minikube dir is up to date
|
||||||
|
if _, err := runCmdInMinikube(ctx, []string{"git", "pull", "origin", "master"}); err != nil {
|
||||||
|
return "", errors.Wrap(err, "running git pull")
|
||||||
|
}
|
||||||
|
mkcmpPath := "out/mkcmp"
|
||||||
|
minikubePath := "out/minikube"
|
||||||
|
if _, err := runCmdInMinikube(ctx, []string{"make", mkcmpPath, minikubePath}); err != nil {
|
||||||
|
return "", errors.Wrap(err, "building minikube and mkcmp at head")
|
||||||
|
}
|
||||||
|
return runCmdInMinikube(ctx, []string{mkcmpPath, minikubePath, fmt.Sprintf("pr://%d", pr)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// runCmdInMinikube runs the cmd and return stdout
|
||||||
|
func runCmdInMinikube(ctx context.Context, command []string) (string, error) {
|
||||||
|
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||||||
|
cmd.Dir = minikubeDir()
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
cmd.Stdout = buf
|
||||||
|
|
||||||
|
log.Printf("Running: %v", cmd.Args)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return "", errors.Wrapf(err, "running %v: %v", cmd.Args, buf.String())
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func minikubeDir() string {
|
||||||
|
return filepath.Join(os.Getenv("HOME"), "minikube")
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 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 monitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-github/github"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client provides the context and client with necessary auth
|
||||||
|
// for interacting with the Github API
|
||||||
|
type Client struct {
|
||||||
|
ctx context.Context
|
||||||
|
*github.Client
|
||||||
|
owner string
|
||||||
|
repo string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a github client with the necessary auth
|
||||||
|
func NewClient(ctx context.Context, owner, repo string) *Client {
|
||||||
|
githubToken := os.Getenv(GithubAccessTokenEnvVar)
|
||||||
|
// Setup the token for github authentication
|
||||||
|
ts := oauth2.StaticTokenSource(
|
||||||
|
&oauth2.Token{AccessToken: githubToken},
|
||||||
|
)
|
||||||
|
tc := oauth2.NewClient(context.Background(), ts)
|
||||||
|
|
||||||
|
// Return a client instance from github
|
||||||
|
client := github.NewClient(tc)
|
||||||
|
return &Client{
|
||||||
|
ctx: ctx,
|
||||||
|
Client: client,
|
||||||
|
owner: owner,
|
||||||
|
repo: repo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommentOnPR comments message on the PR
|
||||||
|
func (g *Client) CommentOnPR(pr int, message string) error {
|
||||||
|
comment := &github.IssueComment{
|
||||||
|
Body: &message,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Creating comment on PR %d: %s", pr, message)
|
||||||
|
_, _, err := g.Client.Issues.CreateComment(g.ctx, g.owner, g.repo, pr, comment)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "creating github comment")
|
||||||
|
}
|
||||||
|
log.Printf("Successfully commented on PR %d.", pr)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpenPRsWithLabel returns all open PRs with the specified label
|
||||||
|
func (g *Client) ListOpenPRsWithLabel(label string) ([]int, error) {
|
||||||
|
validPrs := []int{}
|
||||||
|
prs, _, err := g.Client.PullRequests.List(g.ctx, g.owner, g.repo, &github.PullRequestListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "listing pull requests")
|
||||||
|
}
|
||||||
|
for _, pr := range prs {
|
||||||
|
if prContainsLabel(pr.Labels, label) {
|
||||||
|
validPrs = append(validPrs, pr.GetNumber())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validPrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func prContainsLabel(labels []*github.Label, label string) bool {
|
||||||
|
for _, l := range labels {
|
||||||
|
if l == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if l.GetName() == label {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCommitsExist checks if new commits exist since minikube-pr-bot
|
||||||
|
// commented on the PR. If so, return true.
|
||||||
|
func (g *Client) NewCommitsExist(pr int, login string) (bool, error) {
|
||||||
|
lastCommentTime, err := g.timeOfLastComment(pr, login)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "getting time of last comment by %s on pr %d", login, pr)
|
||||||
|
}
|
||||||
|
lastCommitTime, err := g.timeOfLastCommit(pr)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "getting time of last commit on pr %d", pr)
|
||||||
|
}
|
||||||
|
return lastCommentTime.Before(lastCommitTime), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Client) timeOfLastCommit(pr int) (time.Time, error) {
|
||||||
|
var commits []*github.RepositoryCommit
|
||||||
|
|
||||||
|
page := 0
|
||||||
|
resultsPerPage := 30
|
||||||
|
for {
|
||||||
|
c, _, err := g.Client.PullRequests.ListCommits(g.ctx, g.owner, g.repo, pr, &github.ListOptions{
|
||||||
|
Page: page,
|
||||||
|
PerPage: resultsPerPage,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
commits = append(commits, c...)
|
||||||
|
if len(c) < resultsPerPage {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page++
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCommitTime := time.Time{}
|
||||||
|
for _, c := range commits {
|
||||||
|
if newCommitTime := c.GetCommit().GetAuthor().GetDate(); newCommitTime.After(lastCommitTime) {
|
||||||
|
lastCommitTime = newCommitTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastCommitTime, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Client) timeOfLastComment(pr int, login string) (time.Time, error) {
|
||||||
|
var comments []*github.IssueComment
|
||||||
|
|
||||||
|
page := 0
|
||||||
|
resultsPerPage := 30
|
||||||
|
for {
|
||||||
|
c, _, err := g.Client.Issues.ListComments(g.ctx, g.owner, g.repo, pr, &github.IssueListCommentsOptions{
|
||||||
|
ListOptions: github.ListOptions{
|
||||||
|
Page: page,
|
||||||
|
PerPage: resultsPerPage,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
comments = append(comments, c...)
|
||||||
|
if len(c) < resultsPerPage {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page++
|
||||||
|
}
|
||||||
|
|
||||||
|
// go through comments backwards to find the most recent
|
||||||
|
lastCommentTime := time.Time{}
|
||||||
|
|
||||||
|
for _, c := range comments {
|
||||||
|
if u := c.GetUser(); u != nil {
|
||||||
|
if u.GetLogin() == login {
|
||||||
|
if c.GetCreatedAt().After(lastCommentTime) {
|
||||||
|
lastCommentTime = c.GetCreatedAt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastCommentTime, nil
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
"github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,6 +47,18 @@ func CalculateSizeInMB(humanReadableSize string) (int, error) {
|
||||||
return int(size / units.MiB), nil
|
return int(size / units.MiB), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConvertMBToBytes(mbSize int) int64 {
|
||||||
|
return int64(mbSize) * units.MiB
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertBytesToMB(byteSize int64) int {
|
||||||
|
return int(ConvertUnsignedBytesToMB(uint64(byteSize)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertUnsignedBytesToMB(byteSize uint64) int64 {
|
||||||
|
return int64(byteSize / units.MiB)
|
||||||
|
}
|
||||||
|
|
||||||
// GetBinaryDownloadURL returns a suitable URL for the platform
|
// GetBinaryDownloadURL returns a suitable URL for the platform
|
||||||
func GetBinaryDownloadURL(version, platform string) string {
|
func GetBinaryDownloadURL(version, platform string) string {
|
||||||
switch platform {
|
switch platform {
|
||||||
|
|
|
@ -11,7 +11,6 @@ Generate command completion for a shell
|
||||||
|
|
||||||
### Synopsis
|
### Synopsis
|
||||||
|
|
||||||
|
|
||||||
Outputs minikube shell completion for the given shell (bash, zsh or fish)
|
Outputs minikube shell completion for the given shell (bash, zsh or fish)
|
||||||
|
|
||||||
This depends on the bash-completion binary. Example installation instructions:
|
This depends on the bash-completion binary. Example installation instructions:
|
||||||
|
|
|
@ -26,7 +26,7 @@ minikube start [flags]
|
||||||
--apiserver-names stringArray A set of apiserver names which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine
|
--apiserver-names stringArray A set of apiserver names which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine
|
||||||
--apiserver-port int The apiserver listening port (default 8443)
|
--apiserver-port int The apiserver listening port (default 8443)
|
||||||
--auto-update-drivers If set, automatically updates drivers to the latest version. Defaults to true. (default true)
|
--auto-update-drivers If set, automatically updates drivers to the latest version. Defaults to true. (default true)
|
||||||
--base-image string The base image to use for docker/podman drivers. Intended for local development. (default "gcr.io/k8s-minikube/kicbase:v0.0.12-snapshot3@sha256:1d687ba53e19dbe5fafe4cc18aa07f269ecc4b7b622f2251b5bf569ddb474e9b")
|
--base-image string The base image to use for docker/podman drivers. Intended for local development. (default "gcr.io/k8s-minikube/kicbase:v0.0.13-snapshot1@sha256:4d43acbd0050148d4bc399931f1b15253b5e73815b63a67b8ab4a5c9e523403f")
|
||||||
--cache-images If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none. (default true)
|
--cache-images If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none. (default true)
|
||||||
--cni string CNI plug-in to use. Valid options: auto, bridge, calico, cilium, flannel, kindnet, or path to a CNI manifest (default: auto)
|
--cni string CNI plug-in to use. Valid options: auto, bridge, calico, cilium, flannel, kindnet, or path to a CNI manifest (default: auto)
|
||||||
--container-runtime string The container runtime to be used (docker, cri-o, containerd). (default "docker")
|
--container-runtime string The container runtime to be used (docker, cri-o, containerd). (default "docker")
|
||||||
|
@ -65,7 +65,7 @@ minikube start [flags]
|
||||||
--insecure-registry strings Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.
|
--insecure-registry strings Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.
|
||||||
--install-addons If set, install addons. Defaults to true. (default true)
|
--install-addons If set, install addons. Defaults to true. (default true)
|
||||||
--interactive Allow user prompts for more information (default true)
|
--interactive Allow user prompts for more information (default true)
|
||||||
--iso-url strings Locations to fetch the minikube ISO from. (default [https://storage.googleapis.com/minikube/iso/minikube-v1.13.0.iso,https://github.com/kubernetes/minikube/releases/download/v1.13.0/minikube-v1.13.0.iso,https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.13.0.iso])
|
--iso-url strings Locations to fetch the minikube ISO from. (default [https://storage.googleapis.com/minikube/iso/minikube-v1.13.1.iso,https://github.com/kubernetes/minikube/releases/download/v1.13.1/minikube-v1.13.1.iso,https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.13.1.iso])
|
||||||
--keep-context This will keep the existing kubectl context and will create a minikube context.
|
--keep-context This will keep the existing kubectl context and will create a minikube context.
|
||||||
--kubernetes-version string The Kubernetes version that the minikube VM will use (ex: v1.2.3, 'stable' for v1.19.2, 'latest' for v1.19.2). Defaults to 'stable'.
|
--kubernetes-version string The Kubernetes version that the minikube VM will use (ex: v1.2.3, 'stable' for v1.19.2, 'latest' for v1.19.2). Defaults to 'stable'.
|
||||||
--kvm-gpu Enable experimental NVIDIA GPU support in minikube
|
--kvm-gpu Enable experimental NVIDIA GPU support in minikube
|
||||||
|
|
|
@ -5,7 +5,7 @@ weight: 1
|
||||||
date: 2020-07-15
|
date: 2020-07-15
|
||||||
---
|
---
|
||||||
|
|
||||||
If you have a containerized GCP app with a Kubernetes yaml, you can automatically add your credentials to all your deployed pods dynamically with this minikube addon. You just need to have a credentials file, which can be generated with `gcloud auth login`. If you already have a json credentials file you want specify, use the GOOGLE_APPLICATION_CREDENTIALS environment variable.
|
If you have a containerized GCP app with a Kubernetes yaml, you can automatically add your credentials to all your deployed pods dynamically with this minikube addon. You just need to have a credentials file, which can be generated with `gcloud auth application-default login`. If you already have a json credentials file you want specify, use the GOOGLE_APPLICATION_CREDENTIALS environment variable.
|
||||||
|
|
||||||
- Start a cluster:
|
- Start a cluster:
|
||||||
```
|
```
|
||||||
|
|
|
@ -22,6 +22,7 @@ The NO_PROXY variable here is important: Without setting it, minikube may not be
|
||||||
|
|
||||||
* **192.168.99.0/24**: Used by the minikube VM. Configurable for some hypervisors via `--host-only-cidr`
|
* **192.168.99.0/24**: Used by the minikube VM. Configurable for some hypervisors via `--host-only-cidr`
|
||||||
* **192.168.39.0/24**: Used by the minikube kvm2 driver.
|
* **192.168.39.0/24**: Used by the minikube kvm2 driver.
|
||||||
|
* **192.168.49.0/24**: Used by the minikube docker driver's first cluster.
|
||||||
* **10.96.0.0/12**: Used by service cluster IP's. Configurable via `--service-cluster-ip-range`
|
* **10.96.0.0/12**: Used by service cluster IP's. Configurable via `--service-cluster-ip-range`
|
||||||
|
|
||||||
One important note: If NO_PROXY is required by non-Kubernetes applications, such as Firefox or Chrome, you may want to specifically add the minikube IP to the comma-separated list, as they may not understand IP ranges ([#3827](https://github.com/kubernetes/minikube/issues/3827)).
|
One important note: If NO_PROXY is required by non-Kubernetes applications, such as Firefox or Chrome, you may want to specifically add the minikube IP to the comma-separated list, as they may not understand IP ranges ([#3827](https://github.com/kubernetes/minikube/issues/3827)).
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"- Docs https://docs.docker.com/docker-for-mac/#resources": "",
|
"- Docs https://docs.docker.com/docker-for-mac/#resources": "",
|
||||||
"- Docs https://docs.docker.com/docker-for-windows/#resources": "",
|
"- Docs https://docs.docker.com/docker-for-windows/#resources": "",
|
||||||
"- Ensure your {{.driver_name}} daemon has access to enough CPU/memory resources.": "",
|
"- Ensure your {{.driver_name}} daemon has access to enough CPU/memory resources.": "",
|
||||||
"- Prune unused {{.driver_name}} images, volumes and abandoned containers.": "",
|
"- Prune unused {{.driver_name}} images, volumes, networks and abandoned containers.\n\n\t\t\t\t{{.driver_name}} system prune --volumes": "",
|
||||||
"- Restart your {{.driver_name}} service": "",
|
"- Restart your {{.driver_name}} service": "",
|
||||||
"A VPN or firewall is interfering with HTTP access to the minikube VM. Alternatively, try a different VM driver: https://minikube.sigs.k8s.io/docs/start/": "",
|
"A VPN or firewall is interfering with HTTP access to the minikube VM. Alternatively, try a different VM driver: https://minikube.sigs.k8s.io/docs/start/": "",
|
||||||
"A firewall is blocking Docker the minikube VM from reaching the image repository. You may need to select --image-repository, or use a proxy.": "",
|
"A firewall is blocking Docker the minikube VM from reaching the image repository. You may need to select --image-repository, or use a proxy.": "",
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
"Basic Commands:": "",
|
"Basic Commands:": "",
|
||||||
"Because you are using a Docker driver on {{.operating_system}}, the terminal needs to be open to run it.": "",
|
"Because you are using a Docker driver on {{.operating_system}}, the terminal needs to be open to run it.": "",
|
||||||
"Bind Address: {{.Address}}": "",
|
"Bind Address: {{.Address}}": "",
|
||||||
"Both driver={{.driver}} and vm-driver={{.vmd}} have been set.\n\n Since vm-driver is deprecated, minikube will default to driver={{.driver}}.\n\n If vm-driver is set in the global config, please run \"minikube config unset vm-driver\" to resolve this warning.": "",
|
"Both driver={{.driver}} and vm-driver={{.vmd}} have been set.\n\n Since vm-driver is deprecated, minikube will default to driver={{.driver}}.\n\n If vm-driver is set in the global config, please run \"minikube config unset vm-driver\" to resolve this warning.\n\t\t\t": "",
|
||||||
"CNI plug-in to use. Valid options: auto, bridge, calico, cilium, flannel, kindnet, or path to a CNI manifest (default: auto)": "",
|
"CNI plug-in to use. Valid options: auto, bridge, calico, cilium, flannel, kindnet, or path to a CNI manifest (default: auto)": "",
|
||||||
"Cannot find directory {{.path}} for mount": "",
|
"Cannot find directory {{.path}} for mount": "",
|
||||||
"Cannot use both --output and --format options": "",
|
"Cannot use both --output and --format options": "",
|
||||||
|
@ -78,6 +78,7 @@
|
||||||
"Creating mount {{.name}} ...": "",
|
"Creating mount {{.name}} ...": "",
|
||||||
"Creating {{.driver_name}} {{.machine_type}} (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB) ...": "",
|
"Creating {{.driver_name}} {{.machine_type}} (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB) ...": "",
|
||||||
"Creating {{.driver_name}} {{.machine_type}} (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "",
|
"Creating {{.driver_name}} {{.machine_type}} (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "",
|
||||||
|
"Current context is \"{{.context}}\"": "",
|
||||||
"DEPRECATED, use `driver` instead.": "",
|
"DEPRECATED, use `driver` instead.": "",
|
||||||
"DEPRECATED: Replaced by --cni=bridge": "",
|
"DEPRECATED: Replaced by --cni=bridge": "",
|
||||||
"Default group id used for the mount": "",
|
"Default group id used for the mount": "",
|
||||||
|
@ -102,10 +103,9 @@
|
||||||
"Docker Desktop has less than 2 CPUs configured, but Kubernetes requires at least 2 to be available": "",
|
"Docker Desktop has less than 2 CPUs configured, but Kubernetes requires at least 2 to be available": "",
|
||||||
"Docker Desktop is configured for Windows containers, but Linux containers are required for minikube": "",
|
"Docker Desktop is configured for Windows containers, but Linux containers are required for minikube": "",
|
||||||
"Docker Desktop only has {{.size}}MiB available, less than the required {{.req}}MiB for Kubernetes": "",
|
"Docker Desktop only has {{.size}}MiB available, less than the required {{.req}}MiB for Kubernetes": "",
|
||||||
|
"Docker Desktop only has {{.size}}MiB available, you may encounter application deployment failures.": "",
|
||||||
"Docker has less than 2 CPUs available, but Kubernetes requires at least 2 to be available": "",
|
"Docker has less than 2 CPUs available, but Kubernetes requires at least 2 to be available": "",
|
||||||
"Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.": "",
|
"Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.": "",
|
||||||
"Docker is nearly out of disk space, which may cause deployments to fail! ({{.p}}% of capacity)": "",
|
|
||||||
"Docker is out of disk space! (/var is at {{.p}}% of capacity)": "",
|
|
||||||
"Docs have been saved at - {{.path}}": "",
|
"Docs have been saved at - {{.path}}": "",
|
||||||
"Documentation: {{.url}}": "",
|
"Documentation: {{.url}}": "",
|
||||||
"Done! kubectl is now configured to use \"{{.name}}\" by default": "",
|
"Done! kubectl is now configured to use \"{{.name}}\" by default": "",
|
||||||
|
@ -161,6 +161,7 @@
|
||||||
"Error starting cluster": "",
|
"Error starting cluster": "",
|
||||||
"Error starting mount": "",
|
"Error starting mount": "",
|
||||||
"Error while setting kubectl current context : {{.error}}": "",
|
"Error while setting kubectl current context : {{.error}}": "",
|
||||||
|
"Error while setting kubectl current context: {{.error}}": "",
|
||||||
"Error writing mount pid": "",
|
"Error writing mount pid": "",
|
||||||
"Examples": "",
|
"Examples": "",
|
||||||
"Executing \"{{.command}}\" took an unusually long time: {{.duration}}": "",
|
"Executing \"{{.command}}\" took an unusually long time: {{.duration}}": "",
|
||||||
|
@ -180,7 +181,6 @@
|
||||||
"Failed to delete images": "",
|
"Failed to delete images": "",
|
||||||
"Failed to delete images from config": "",
|
"Failed to delete images from config": "",
|
||||||
"Failed to enable container runtime": "",
|
"Failed to enable container runtime": "",
|
||||||
"Failed to get API Server URL": "",
|
|
||||||
"Failed to get bootstrapper": "",
|
"Failed to get bootstrapper": "",
|
||||||
"Failed to get command runner": "",
|
"Failed to get command runner": "",
|
||||||
"Failed to get image map": "",
|
"Failed to get image map": "",
|
||||||
|
@ -299,7 +299,7 @@
|
||||||
"One of 'yaml' or 'json'.": "",
|
"One of 'yaml' or 'json'.": "",
|
||||||
"Only alphanumeric and dashes '-' are permitted. Minimum 1 character, starting with alphanumeric.": "",
|
"Only alphanumeric and dashes '-' are permitted. Minimum 1 character, starting with alphanumeric.": "",
|
||||||
"Open the addons URL with https instead of http": "",
|
"Open the addons URL with https instead of http": "",
|
||||||
"Open the service URL with https instead of http": "",
|
"Open the service URL with https instead of http (defaults to \\\"false\\\")": "",
|
||||||
"Opening Kubernetes service {{.namespace_name}}/{{.service_name}} in default browser...": "",
|
"Opening Kubernetes service {{.namespace_name}}/{{.service_name}} in default browser...": "",
|
||||||
"Opening service {{.namespace_name}}/{{.service_name}} in default browser...": "",
|
"Opening service {{.namespace_name}}/{{.service_name}} in default browser...": "",
|
||||||
"Opening {{.url}} in your default browser...": "",
|
"Opening {{.url}} in your default browser...": "",
|
||||||
|
@ -307,7 +307,7 @@
|
||||||
"Operations on nodes": "",
|
"Operations on nodes": "",
|
||||||
"Options: {{.options}}": "",
|
"Options: {{.options}}": "",
|
||||||
"Output format. Accepted values: [json]": "",
|
"Output format. Accepted values: [json]": "",
|
||||||
"Outputs minikube shell completion for the given shell (bash, zsh or fish)\n\n\tThis depends on the bash-completion binary. Example installation instructions:\n\tOS X:\n\t\t$ brew install bash-completion\n\t\t$ source $(brew --prefix)/etc/bash_completion\n\t\t$ minikube completion bash \u003e ~/.minikube-completion # for bash users\n\t\t$ minikube completion zsh \u003e ~/.minikube-completion # for zsh users\n\t\t$ source ~/.minikube-completion\n\t\t$ minikube completion fish \u003e ~/.config/fish/completions/minikube.fish # for fish users\n\tUbuntu:\n\t\t$ apt-get install bash-completion\n\t\t$ source /etc/bash-completion\n\t\t$ source \u003c(minikube completion bash) # for bash users\n\t\t$ source \u003c(minikube completion zsh) # for zsh users\n\t\t$ minikube completion fish \u003e ~/.config/fish/completions/minikube.fish # for fish users\n\n\tAdditionally, you may want to output the completion to a file and source in your .bashrc\n\n\tNote for zsh users: [1] zsh completions are only supported in versions of zsh \u003e= 5.2\n\tNote for fish users: [2] please refer to this docs for more details https://fishshell.com/docs/current/#tab-completion": "",
|
"Outputs minikube shell completion for the given shell (bash, zsh or fish)\n\n\tThis depends on the bash-completion binary. Example installation instructions:\n\tOS X:\n\t\t$ brew install bash-completion\n\t\t$ source $(brew --prefix)/etc/bash_completion\n\t\t$ minikube completion bash \u003e ~/.minikube-completion # for bash users\n\t\t$ minikube completion zsh \u003e ~/.minikube-completion # for zsh users\n\t\t$ source ~/.minikube-completion\n\t\t$ minikube completion fish \u003e ~/.config/fish/completions/minikube.fish # for fish users\n\tUbuntu:\n\t\t$ apt-get install bash-completion\n\t\t$ source /etc/bash-completion\n\t\t$ source \u003c(minikube completion bash) # for bash users\n\t\t$ source \u003c(minikube completion zsh) # for zsh users\n\t\t$ minikube completion fish \u003e ~/.config/fish/completions/minikube.fish # for fish users\n\n\tAdditionally, you may want to output the completion to a file and source in your .bashrc\n\n\tNote for zsh users: [1] zsh completions are only supported in versions of zsh \u003e= 5.2\n\tNote for fish users: [2] please refer to this docs for more details https://fishshell.com/docs/current/#tab-completion\n": "",
|
||||||
"Pause": "",
|
"Pause": "",
|
||||||
"Paused {{.count}} containers": "",
|
"Paused {{.count}} containers": "",
|
||||||
"Paused {{.count}} containers in: {{.namespaces}}": "",
|
"Paused {{.count}} containers in: {{.namespaces}}": "",
|
||||||
|
@ -321,11 +321,11 @@
|
||||||
"Please install the minikube hyperkit VM driver, or select an alternative --driver": "",
|
"Please install the minikube hyperkit VM driver, or select an alternative --driver": "",
|
||||||
"Please install the minikube kvm2 VM driver, or select an alternative --driver": "",
|
"Please install the minikube kvm2 VM driver, or select an alternative --driver": "",
|
||||||
"Please make sure the service you are looking for is deployed or is in the correct namespace.": "",
|
"Please make sure the service you are looking for is deployed or is in the correct namespace.": "",
|
||||||
"Please re-eval your docker-env, To ensure your environment variables have updated ports:\n\n\t'minikube -p {{.profile_name}} docker-env'": "",
|
"Please re-eval your docker-env, To ensure your environment variables have updated ports:\n\n\t'minikube -p {{.profile_name}} docker-env'\n\n\t": "",
|
||||||
"Please re-eval your podman-env, To ensure your environment variables have updated ports:\n\n\t'minikube -p {{.profile_name}} podman-env'": "",
|
"Please re-eval your podman-env, To ensure your environment variables have updated ports:\n\n\t'minikube -p {{.profile_name}} podman-env'\n\n\t": "",
|
||||||
"Please see {{.documentation_url}} for more details": "",
|
"Please see {{.documentation_url}} for more details": "",
|
||||||
"Please specify the directory to be mounted: \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "",
|
"Please specify the directory to be mounted: \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "",
|
||||||
"Please visit the following link for documentation around this: \n\thttps://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages": "",
|
"Please visit the following link for documentation around this: \n\thttps://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages\n": "",
|
||||||
"Populates the specified folder with documentation in markdown about minikube": "",
|
"Populates the specified folder with documentation in markdown about minikube": "",
|
||||||
"PowerShell is running in constrained mode, which is incompatible with Hyper-V scripting.": "",
|
"PowerShell is running in constrained mode, which is incompatible with Hyper-V scripting.": "",
|
||||||
"Powering off \"{{.profile_name}}\" via SSH ...": "",
|
"Powering off \"{{.profile_name}}\" via SSH ...": "",
|
||||||
|
@ -400,7 +400,7 @@
|
||||||
"Show only log entries which point to known problems": "",
|
"Show only log entries which point to known problems": "",
|
||||||
"Show only the most recent journal entries, and continuously print new entries as they are appended to the journal.": "",
|
"Show only the most recent journal entries, and continuously print new entries as they are appended to the journal.": "",
|
||||||
"Skipped switching kubectl context for {{.profile_name}} because --keep-context was set.": "",
|
"Skipped switching kubectl context for {{.profile_name}} because --keep-context was set.": "",
|
||||||
"Some dashboard features require the metrics-server addon. To enable all features please run:\n\n\tminikube{{.profileArg}} addons enable metrics-server": "",
|
"Some dashboard features require the metrics-server addon. To enable all features please run:\n\n\tminikube{{.profileArg}} addons enable metrics-server\t\n\n": "",
|
||||||
"Sorry, Kubernetes {{.k8sVersion}} requires conntrack to be installed in root's path": "",
|
"Sorry, Kubernetes {{.k8sVersion}} requires conntrack to be installed in root's path": "",
|
||||||
"Sorry, completion support is not yet implemented for {{.name}}": "",
|
"Sorry, completion support is not yet implemented for {{.name}}": "",
|
||||||
"Sorry, please set the --output flag to one of the following valid options: [text,json]": "",
|
"Sorry, please set the --output flag to one of the following valid options: [text,json]": "",
|
||||||
|
@ -622,7 +622,7 @@
|
||||||
"Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.": "",
|
"Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.": "",
|
||||||
"Your minikube config refers to an unsupported driver. Erase ~/.minikube, and try again.": "",
|
"Your minikube config refers to an unsupported driver. Erase ~/.minikube, and try again.": "",
|
||||||
"Your minikube vm is not running, try minikube start.": "",
|
"Your minikube vm is not running, try minikube start.": "",
|
||||||
"Your user lacks permissions to the minikube profile directory. Run: 'sudo chown -R $USER $HOME/.minikube; chmod -R u+wrx $HOME/.minikube' to fix": "",
|
"[WARNING] For full functionality, the 'csi-hostpath-driver' addon requires the 'volumesnapshots' addon to be enabled.\n\nYou can enable 'volumesnapshots' addon by running: 'minikube addons enable volumesnapshots'\n": "",
|
||||||
"addon '{{.name}}' is currently not enabled.\nTo enable this addon run:\nminikube addons enable {{.name}}": "",
|
"addon '{{.name}}' is currently not enabled.\nTo enable this addon run:\nminikube addons enable {{.name}}": "",
|
||||||
"addon '{{.name}}' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "",
|
"addon '{{.name}}' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "",
|
||||||
"addons modifies minikube addons files using subcommands like \"minikube addons enable dashboard\"": "",
|
"addons modifies minikube addons files using subcommands like \"minikube addons enable dashboard\"": "",
|
||||||
|
@ -667,7 +667,7 @@
|
||||||
"minikube is exiting due to an error. If the above message is not useful, open an issue:": "",
|
"minikube is exiting due to an error. If the above message is not useful, open an issue:": "",
|
||||||
"minikube is missing files relating to your guest environment. This can be fixed by running 'minikube delete'": "",
|
"minikube is missing files relating to your guest environment. This can be fixed by running 'minikube delete'": "",
|
||||||
"minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.": "",
|
"minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.": "",
|
||||||
"minikube is unable to connect to the VM: {{.error}}\n\n\tThis is likely due to one of two reasons:\n\n\t- VPN or firewall interference\n\t- {{.hypervisor}} network configuration issue\n\n\tSuggested workarounds:\n\n\t- Disable your local VPN or firewall software\n\t- Configure your local VPN or firewall to allow access to {{.ip}}\n\t- Restart or reinstall {{.hypervisor}}\n\t- Use an alternative --vm-driver\n\t- Use --force to override this connectivity check": "",
|
"minikube is unable to connect to the VM: {{.error}}\n\n\tThis is likely due to one of two reasons:\n\n\t- VPN or firewall interference\n\t- {{.hypervisor}} network configuration issue\n\n\tSuggested workarounds:\n\n\t- Disable your local VPN or firewall software\n\t- Configure your local VPN or firewall to allow access to {{.ip}}\n\t- Restart or reinstall {{.hypervisor}}\n\t- Use an alternative --vm-driver\n\t- Use --force to override this connectivity check\n\t": "",
|
||||||
"minikube profile was successfully set to {{.profile_name}}": "",
|
"minikube profile was successfully set to {{.profile_name}}": "",
|
||||||
"minikube provisions and manages local Kubernetes clusters optimized for development workflows.": "",
|
"minikube provisions and manages local Kubernetes clusters optimized for development workflows.": "",
|
||||||
"minikube quickly sets up a local Kubernetes cluster": "",
|
"minikube quickly sets up a local Kubernetes cluster": "",
|
||||||
|
@ -715,6 +715,7 @@
|
||||||
"version yaml failure": "",
|
"version yaml failure": "",
|
||||||
"zsh completion failed": "",
|
"zsh completion failed": "",
|
||||||
"{{ .name }}: {{ .rejection }}": "",
|
"{{ .name }}: {{ .rejection }}": "",
|
||||||
|
"{{.Driver}} is currently using the {{.StorageDriver}} storage driver, consider switching to overlay2 for better performance": "",
|
||||||
"{{.count}} nodes stopped.": "",
|
"{{.count}} nodes stopped.": "",
|
||||||
"{{.driver_name}} \"{{.cluster}}\" {{.machine_type}} is missing, will recreate.": "",
|
"{{.driver_name}} \"{{.cluster}}\" {{.machine_type}} is missing, will recreate.": "",
|
||||||
"{{.driver_name}} couldn't proceed because {{.driver_name}} service is not healthy.": "",
|
"{{.driver_name}} couldn't proceed because {{.driver_name}} service is not healthy.": "",
|
||||||
|
@ -725,6 +726,8 @@
|
||||||
"{{.name}} has no available configuration options": "",
|
"{{.name}} has no available configuration options": "",
|
||||||
"{{.name}} is already running": "",
|
"{{.name}} is already running": "",
|
||||||
"{{.name}} was successfully configured": "",
|
"{{.name}} was successfully configured": "",
|
||||||
|
"{{.n}} is nearly out of disk space, which may cause deployments to fail! ({{.p}}% of capacity)": "",
|
||||||
|
"{{.n}} is out of disk space! (/var is at {{.p}}% of capacity)": "",
|
||||||
"{{.ocibin}} is taking an unsually long time to respond, consider restarting {{.ocibin}}": "",
|
"{{.ocibin}} is taking an unsually long time to respond, consider restarting {{.ocibin}}": "",
|
||||||
"{{.path}} is version {{.client_version}}, which may have incompatibilites with Kubernetes {{.cluster_version}}.": "",
|
"{{.path}} is version {{.client_version}}, which may have incompatibilites with Kubernetes {{.cluster_version}}.": "",
|
||||||
"{{.prefix}}minikube {{.version}} on {{.platform}}": "",
|
"{{.prefix}}minikube {{.version}} on {{.platform}}": "",
|
||||||
|
|
Loading…
Reference in New Issue