diff --git a/.github/workflows/iso.yml b/.github/workflows/iso.yml index 785ab71a14..7294872fc2 100644 --- a/.github/workflows/iso.yml +++ b/.github/workflows/iso.yml @@ -64,11 +64,6 @@ jobs: echo workspace $GITHUB_WORKSPACE echo "end of debug stuff" 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 run: | whoami @@ -146,4 +141,4 @@ jobs: if [ "$numFail" -gt 0 ];then echo "*** $numFail Failed ***";exit 2;fi if [ "$numPass" -eq 0 ];then echo "*** 0 Passed! ***";exit 2;fi if [ "$numPass" -lt 32 ];then echo "*** Failed to pass at least 32 ! ***";exit 2;fi - if [ "$numPass" -eq 0 ];then echo "*** Passed! ***";exit 0;fi \ No newline at end of file + if [ "$numPass" -eq 0 ];then echo "*** Passed! ***";exit 0;fi diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 5521378f3b..7aea4691f4 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -412,7 +412,7 @@ jobs: echo "---------------- ${numFail} Failures :( ----------------------------" echo $failedTests echo "-------------------------------------------------------" - If ($numFail -gt 0){ exit 2 } + If ($numFail -gt 0){ exit 2 } If ($numPass -eq 0){ exit 2 } If ($numPass -lt 33){ exit 2 } If ($numFail -eq 0){ exit 0 } @@ -429,7 +429,7 @@ jobs: shell: powershell run: | echo $env:computerName - ls + ls $ErrorActionPreference = "SilentlyContinue" cd minikube_binaries ls @@ -464,14 +464,14 @@ jobs: $docker_running = $? } Write-Output "Docker is running" - docker system prune -f + docker system prune -f - name: Info continue-on-error: true shell: powershell run: | $ErrorActionPreference = "SilentlyContinue" cd minikube_binaries - ls + ls echo $env:computername Get-WmiObject -class Win32_ComputerSystem - uses: actions/setup-go@v2 @@ -483,7 +483,7 @@ jobs: shell: powershell run: | $ErrorActionPreference = "SilentlyContinue" - (New-Object Net.WebClient).DownloadFile("https://github.com/medyagh/gopogh/releases/download/v0.2.4/gopogh.exe", "C:\ProgramData\chocolatey\bin\gopogh.exe") + (New-Object Net.WebClient).DownloadFile("https://github.com/medyagh/gopogh/releases/download/v0.2.4/gopogh.exe", "C:\ProgramData\chocolatey\bin\gopogh.exe") choco install -y kubernetes-cli choco install -y jq choco install -y caffeine @@ -549,7 +549,7 @@ jobs: echo "---------------- ${numFail} Failures :( ----------------------------" echo $failedTests echo "-------------------------------------------------------" - If ($numFail -gt 0){ exit 2 } + If ($numFail -gt 0){ exit 2 } If ($numPass -eq 0){ exit 2 } If ($numPass -lt 33){ exit 2 } If ($numFail -eq 0){ exit 0 } @@ -775,11 +775,11 @@ jobs: run: | hostname VBoxManage --version - sysctl hw.physicalcpu hw.logicalcpu + sysctl hw.physicalcpu hw.logicalcpu - name: Disable firewall run: | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - sudo /usr/libexec/ApplicationFirewall/socketfilterfw -k + sudo /usr/libexec/ApplicationFirewall/socketfilterfw -k - name: Download Binaries uses: actions/download-artifact@v1 with: @@ -966,7 +966,7 @@ jobs: run: | hostname VBoxManage --version - sysctl hw.physicalcpu hw.logicalcpu + sysctl hw.physicalcpu hw.logicalcpu - name: Disable firewall run: | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off @@ -1150,7 +1150,7 @@ jobs: run: | hostname VBoxManage --version - sysctl hw.physicalcpu hw.logicalcpu + sysctl hw.physicalcpu hw.logicalcpu - name: Disable firewall run: | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off @@ -1247,4 +1247,4 @@ jobs: - uses: actions/upload-artifact@v1 with: name: all_reports - path: all_reports + path: all_reports \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 21cd5e5a04..cbb271de0d 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -410,7 +410,7 @@ jobs: echo "---------------- ${numFail} Failures :( ----------------------------" echo $failedTests echo "-------------------------------------------------------" - If ($numFail -gt 0){ exit 2 } + If ($numFail -gt 0){ exit 2 } If ($numPass -eq 0){ exit 2 } If ($numPass -lt 33){ exit 2 } If ($numFail -eq 0){ exit 0 } @@ -427,7 +427,7 @@ jobs: shell: powershell run: | echo $env:computerName - ls + ls $ErrorActionPreference = "SilentlyContinue" cd minikube_binaries ls @@ -462,14 +462,14 @@ jobs: $docker_running = $? } Write-Output "Docker is running" - docker system prune -f + docker system prune -f - name: Info continue-on-error: true shell: powershell run: | $ErrorActionPreference = "SilentlyContinue" cd minikube_binaries - ls + ls echo $env:computername Get-WmiObject -class Win32_ComputerSystem - uses: actions/setup-go@v2 @@ -481,7 +481,7 @@ jobs: shell: powershell run: | $ErrorActionPreference = "SilentlyContinue" - (New-Object Net.WebClient).DownloadFile("https://github.com/medyagh/gopogh/releases/download/v0.2.4/gopogh.exe", "C:\ProgramData\chocolatey\bin\gopogh.exe") + (New-Object Net.WebClient).DownloadFile("https://github.com/medyagh/gopogh/releases/download/v0.2.4/gopogh.exe", "C:\ProgramData\chocolatey\bin\gopogh.exe") choco install -y kubernetes-cli choco install -y jq choco install -y caffeine @@ -547,7 +547,7 @@ jobs: echo "---------------- ${numFail} Failures :( ----------------------------" echo $failedTests echo "-------------------------------------------------------" - If ($numFail -gt 0){ exit 2 } + If ($numFail -gt 0){ exit 2 } If ($numPass -eq 0){ exit 2 } If ($numPass -lt 33){ exit 2 } If ($numFail -eq 0){ exit 0 } @@ -773,11 +773,11 @@ jobs: run: | hostname VBoxManage --version - sysctl hw.physicalcpu hw.logicalcpu + sysctl hw.physicalcpu hw.logicalcpu - name: Disable firewall run: | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off - sudo /usr/libexec/ApplicationFirewall/socketfilterfw -k + sudo /usr/libexec/ApplicationFirewall/socketfilterfw -k - name: Download Binaries uses: actions/download-artifact@v1 with: @@ -964,7 +964,7 @@ jobs: run: | hostname VBoxManage --version - sysctl hw.physicalcpu hw.logicalcpu + sysctl hw.physicalcpu hw.logicalcpu - name: Disable firewall run: | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off @@ -1148,7 +1148,7 @@ jobs: run: | hostname VBoxManage --version - sysctl hw.physicalcpu hw.logicalcpu + sysctl hw.physicalcpu hw.logicalcpu - name: Disable firewall run: | sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate off @@ -1245,4 +1245,4 @@ jobs: - uses: actions/upload-artifact@v1 with: name: all_reports - path: all_reports + path: all_reports \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4398a816c4..3959a82268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # 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 ## Features diff --git a/Makefile b/Makefile index 1592fe5f0a..56a3d7e5ae 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ # Bump these on release - and please check ISO_VERSION for correctness. VERSION_MAJOR ?= 1 VERSION_MINOR ?= 13 -VERSION_BUILD ?= 0 +VERSION_BUILD ?= 1 RAW_VERSION=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_BUILD) 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) # 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 DEB_VERSION ?= $(subst -,~,$(RAW_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" @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: ---------------------------" +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 || true +endif .PHONY: 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) $(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@) 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 $@") $(Q)PATH="$(PATH)$(PATHSEP)$(GOPATH)$(DIRSEP)bin" go-bindata -nomemcopy -o $@ -pkg assets deploy/addons/... $(Q)-gofmt -s -w $@ @@ -344,7 +350,7 @@ pkg/minikube/translate/translations.go: $(shell find "translations/" -type f) ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y) $(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@) 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 $@") $(Q)PATH="$(PATH)$(PATHSEP)$(GOPATH)$(DIRSEP)bin" go-bindata -nomemcopy -o $@ -pkg translate translations/... $(Q)-gofmt -s -w $@ @@ -579,7 +585,7 @@ storage-provisioner-image: out/storage-provisioner-$(GOARCH) ## Build storage-pr .PHONY: kic-base-image kic-base-image: ## builds the base image used for kic. 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) 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: GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/mkcmp/main.go -.PHONY: out/performance-monitor -out/performance-monitor: - GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/monitor/monitor.go +.PHONY: out/performance-bot +out/performance-bot: + GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ cmd/performance/pr-bot/bot.go .PHONY: compare compare: out/mkcmp out/minikube diff --git a/cmd/minikube/cmd/completion.go b/cmd/minikube/cmd/completion.go index c2e083e6a5..0035800fec 100644 --- a/cmd/minikube/cmd/completion.go +++ b/cmd/minikube/cmd/completion.go @@ -28,8 +28,7 @@ import ( "k8s.io/minikube/pkg/minikube/reason" ) -const longDescription = ` - Outputs minikube shell completion for the given shell (bash, zsh or fish) +const longDescription = `Outputs minikube shell completion for the given shell (bash, zsh or fish) This depends on the bash-completion binary. Example installation instructions: OS X: diff --git a/cmd/minikube/cmd/config/configure.go b/cmd/minikube/cmd/config/configure.go index 25679e2d38..5b4d5301b6 100644 --- a/cmd/minikube/cmd/config/configure.go +++ b/cmd/minikube/cmd/config/configure.go @@ -32,8 +32,8 @@ import ( var addonsConfigureCmd = &cobra.Command{ Use: "configure ADDON_NAME", - Short: "Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list ", - Long: "Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list ", + Short: "Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list", + Long: "Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list", Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { exit.Message(reason.Usage, "usage: minikube addons configure ADDON_NAME") diff --git a/cmd/minikube/cmd/config/profile_list.go b/cmd/minikube/cmd/config/profile_list.go index 86e30b9eed..8384408c8a 100644 --- a/cmd/minikube/cmd/config/profile_list.go +++ b/cmd/minikube/cmd/config/profile_list.go @@ -23,6 +23,7 @@ import ( "strconv" "strings" + "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/kverify" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" @@ -31,6 +32,7 @@ import ( "k8s.io/minikube/pkg/minikube/reason" "k8s.io/minikube/pkg/minikube/style" + "github.com/docker/machine/libmachine" "github.com/golang/glog" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" @@ -54,96 +56,114 @@ var profileListCmd = &cobra.Command{ }, } -var printProfilesTable = func() { - var validData [][]string +func printProfilesTable() { + 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.SetHeader([]string{"Profile", "VM Driver", "Runtime", "IP", "Port", "Version", "Status"}) table.SetAutoFormatHeaders(false) table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true}) 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) if err != nil { exit.Error(reason.GuestCpConfig, "error getting primary control plane", err) } - p.Status, err = machine.Status(api, driver.MachineName(*p.Config, cp)) - if err != nil { - 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}) + + 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}) + } + return data +} + +func warnInvalidProfiles(invalidProfiles []*config.Profile) { + if invalidProfiles == nil { + return } - table.AppendBulk(validData) - table.Render() - - if invalidProfiles != nil { - out.WarningT("Found {{.number}} invalid profile(s) ! ", out.V{"number": len(invalidProfiles)}) - for _, p := range invalidProfiles { - out.ErrT(style.Empty, "\t "+p.Name) - } - out.ErrT(style.Tip, "You can delete them using the following command(s): ") - for _, p := range invalidProfiles { - out.Err(fmt.Sprintf("\t $ minikube delete -p %s \n", p.Name)) - } - + out.WarningT("Found {{.number}} invalid profile(s) ! ", out.V{"number": len(invalidProfiles)}) + for _, p := range invalidProfiles { + out.ErrT(style.Empty, "\t "+p.Name) } - if err != nil { - glog.Warningf("error loading profiles: %v", err) + out.ErrT(style.Tip, "You can delete them using the following command(s): ") + for _, p := range invalidProfiles { + out.Err(fmt.Sprintf("\t $ minikube delete -p %s \n", p.Name)) } } -var printProfilesJSON = func() { - api, err := machine.NewAPIClient() - if err != nil { - glog.Errorf("failed to get machine api client %v", err) - } - defer api.Close() - +func printProfilesJSON() { 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 - 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{}{} + updateProfilesStatus(validProfiles) + var body = map[string]interface{}{} if err == nil || config.IsNotExist(err) { - body["valid"] = valid - body["invalid"] = invalid + body["valid"] = profilesOrDefault(validProfiles) + body["invalid"] = profilesOrDefault(invalidProfiles) jsonString, _ := json.Marshal(body) out.String(string(jsonString)) } 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() { profileListCmd.Flags().StringVarP(&output, "output", "o", "table", "The output format. One of 'json', 'table'") ProfileCmd.AddCommand(profileListCmd) diff --git a/cmd/minikube/cmd/delete.go b/cmd/minikube/cmd/delete.go index 33a31488c1..e819fec0f3 100644 --- a/cmd/minikube/cmd/delete.go +++ b/cmd/minikube/cmd/delete.go @@ -91,7 +91,6 @@ func init() { if err := viper.BindPFlags(deleteCmd.Flags()); err != nil { exit.Error(reason.InternalBindFlags, "unable to bind flags", err) } - RootCmd.AddCommand(deleteCmd) } // 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) } + 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 { // podman prune does not support --filter return diff --git a/cmd/minikube/cmd/mount.go b/cmd/minikube/cmd/mount.go index 8d268d1cc2..f59b3ca4a7 100644 --- a/cmd/minikube/cmd/mount.go +++ b/cmd/minikube/cmd/mount.go @@ -110,7 +110,7 @@ var mountCmd = &cobra.Command{ var ip net.IP var err error if mountIP == "" { - ip, err = cluster.HostIP(co.CP.Host) + ip, err = cluster.HostIP(co.CP.Host, co.Config.Name) if err != nil { exit.Error(reason.IfHostIP, "Error getting the host IP address to use from within the VM", err) } diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index fc3acd592d..8975cd787b 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -39,6 +39,7 @@ import ( gopshost "github.com/shirou/gopsutil/host" "github.com/spf13/cobra" "github.com/spf13/viper" + cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config" "k8s.io/minikube/pkg/drivers/kic/oci" "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()}) exit.Message(reason.Usage, "Only alphanumeric and dashes '-' are permitted. Minimum 1 character, starting with alphanumeric.") } + existing, err := config.Load(ClusterFlagValue()) 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 { @@ -167,7 +173,24 @@ func runStart(cmd *cobra.Command, args []string) { validateSpecifiedDriver(existing) validateKubernetesVersion(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) if err != nil { node.ExitIfFatal(err) @@ -516,6 +539,7 @@ func kubectlVersion(path string) (string, error) { 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) { // Technically unrelated, but important to perform before detection 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.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() _, err = config.Load(cname) @@ -805,7 +829,7 @@ func memoryLimits(drvName string) (int, int, error) { if err != nil { return -1, -1, err } - containerLimit = int(s.TotalMemory / 1024 / 1024) + containerLimit = util.ConvertBytesToMB(s.TotalMemory) } 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 { paramVersion := viper.GetString(kubernetesVersion) diff --git a/cmd/minikube/cmd/start_test.go b/cmd/minikube/cmd/start_test.go index 8c315b375c..a1071c28f9 100644 --- a/cmd/minikube/cmd/start_test.go +++ b/cmd/minikube/cmd/start_test.go @@ -23,8 +23,10 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + cfg "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/driver" "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) + } + }) + } +} diff --git a/cmd/minikube/cmd/stop.go b/cmd/minikube/cmd/stop.go index 72dbce79a0..dc595cff91 100644 --- a/cmd/minikube/cmd/stop.go +++ b/cmd/minikube/cmd/stop.go @@ -60,8 +60,6 @@ func init() { if err := viper.GetViper().BindPFlags(stopCmd.Flags()); err != nil { exit.Error(reason.InternalFlagsBind, "unable to bind flags", err) } - - RootCmd.AddCommand(stopCmd) } // runStop handles the executes the flow of "minikube stop" diff --git a/cmd/minikube/cmd/update-context.go b/cmd/minikube/cmd/update-context.go index 70f3f2e079..b9659795cd 100644 --- a/cmd/minikube/cmd/update-context.go +++ b/cmd/minikube/cmd/update-context.go @@ -45,5 +45,11 @@ var updateContextCmd = &cobra.Command{ } else { 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}) + } }, } diff --git a/cmd/minikube/main.go b/cmd/minikube/main.go index 1f379790c5..71bee8516f 100644 --- a/cmd/minikube/main.go +++ b/cmd/minikube/main.go @@ -31,6 +31,9 @@ import ( // Register drivers _ "k8s.io/minikube/pkg/minikube/registry/drvs" + // Force exp dependency + _ "golang.org/x/exp/ebnf" + mlog "github.com/docker/machine/libmachine/log" "github.com/golang/glog" diff --git a/cmd/performance/pr-bot/bot.go b/cmd/performance/pr-bot/bot.go index 174c10d9e4..340c4ef8f4 100644 --- a/cmd/performance/pr-bot/bot.go +++ b/cmd/performance/pr-bot/bot.go @@ -18,12 +18,17 @@ package main import ( "context" + "fmt" "log" "time" + + "github.com/pkg/errors" + "k8s.io/minikube/pkg/perf/monitor" ) func main() { for { + log.Print("~~~~~~~~~ Starting performance analysis ~~~~~~~~~~~~~~") if err := analyzePerformance(context.Background()); err != nil { log.Printf("error executing performance analysis: %v", err) } @@ -36,5 +41,32 @@ func main() { // 2. running mkcmp against those PRs // 3. commenting results on those PRs 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 } diff --git a/deploy/addons/gcp-auth/gcp-auth-webhook.yaml b/deploy/addons/gcp-auth/gcp-auth-webhook.yaml index cb06808cc7..81f4de2cc1 100644 --- a/deploy/addons/gcp-auth/gcp-auth-webhook.yaml +++ b/deploy/addons/gcp-auth/gcp-auth-webhook.yaml @@ -131,10 +131,17 @@ metadata: app: gcp-auth webhooks: - name: gcp-auth-mutate.k8s.io + failurePolicy: Fail objectSelector: matchExpressions: - key: gcp-auth-skip-secret operator: DoesNotExist + namespaceSelector: + matchExpressions: + - key: name + operator: NotIn + values: + - kube-system sideEffects: None admissionReviewVersions: ["v1","v1beta1"] clientConfig: diff --git a/deploy/kicbase/10-network-security.conf b/deploy/kicbase/10-network-security.conf new file mode 100644 index 0000000000..3d9c71c3e7 --- /dev/null +++ b/deploy/kicbase/10-network-security.conf @@ -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 diff --git a/deploy/kicbase/Dockerfile b/deploy/kicbase/Dockerfile index 776a036013..13b32a3629 100644 --- a/deploy/kicbase/Dockerfile +++ b/deploy/kicbase/Dockerfile @@ -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 -# 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 # could be changed to any debian that can run systemd -FROM kindest/base:v20200430-2c0eee40 as base 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 \ gnupg \ sudo \ docker.io \ + containerd \ openssh-server \ dnsutils \ runc \ # libglib2.0-0 is required for conmon, which is required for podman - libglib2.0-0 \ - # removing kind's crictl config - && rm /etc/crictl.yaml + libglib2.0-0 # 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" && \ 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-get install -y --no-install-recommends containers-common catatonit conmon containernetworking-plugins podman-plugins varlink + apt-key add - < Release.key && \ + 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 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 && \ - apt-key add - < Release.key && apt-get update && \ - apt-get install -y --no-install-recommends cri-o=1.18.3~3 + apt-key add - < Release.key && \ + clean-install cri-o=1.18.3~3 # install podman 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 && \ - apt-key add - < afbjorklund-public.key.asc && apt-get update && \ - apt-get install -y --no-install-recommends podman=1.9.3~1 + apt-key add - < afbjorklund-public.key.asc && \ + 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 COPY automount/minikube-automount /usr/sbin/minikube-automount 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 RUN mkdir -p /kind # Deleting leftovers -RUN apt-get clean -y && rm -rf \ - /var/cache/debconf/* \ - /var/lib/apt/lists/* \ - /var/log/* \ - /tmp/* \ - /var/tmp/* \ +RUN rm -rf \ /usr/share/doc/* \ /usr/share/man/* \ /usr/share/local/* \ diff --git a/deploy/kicbase/clean-install b/deploy/kicbase/clean-install new file mode 100755 index 0000000000..33b3238b75 --- /dev/null +++ b/deploy/kicbase/clean-install @@ -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/* diff --git a/deploy/minikube/releases.json b/deploy/minikube/releases.json index cfd1fc148b..a37571ded3 100644 --- a/deploy/minikube/releases.json +++ b/deploy/minikube/releases.json @@ -1,4 +1,12 @@ [ + { + "name": "v1.13.1", + "checksums": { + "darwin": "cc7eaadea2becc48eee78136f8d569df55a28c46d58d1c8bb434895382aced78", + "linux": "3564b685f8d797df78ebfa2f5b34c99b3c77b0d1f49eab6aab37500f1ba61d98", + "windows": "0d315ec21ca8a34eff5fa4cc478c09ed2d48ae88b3c5d586df9de111ac414d44" + } + }, { "name": "v1.13.0", "checksums": { diff --git a/go.mod b/go.mod index 225bdf9537..6170d4656e 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/google/go-cmp v0.4.1 github.com/google/go-containerregistry v0.0.0-20200601195303-96cf69f03a3c 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/uuid v1.1.1 github.com/googleapis/gnostic v0.3.0 // indirect @@ -72,6 +73,7 @@ require ( github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 golang.org/x/build v0.0.0-20190927031335-2835ba2e683f 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/sync v0.0.0-20200317015054-43a5402ce75a golang.org/x/sys v0.0.0-20200523222454-059865788121 diff --git a/go.sum b/go.sum index 38b4e9aed3..854420fd06 100644 --- a/go.sum +++ b/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/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= 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/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 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-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-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= 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-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= diff --git a/hack/jenkins/release_github_page.sh b/hack/jenkins/release_github_page.sh index 676fea3942..49cbf197a3 100755 --- a/hack/jenkins/release_github_page.sh +++ b/hack/jenkins/release_github_page.sh @@ -81,7 +81,7 @@ for path in $(gsutil ls "gs://${ISO_BUCKET}/minikube-v${VERSION}*" || true); do done # 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 until [ $n -ge 5 ] do diff --git a/hack/kubernetes_version/update_kubernetes_version.go b/hack/kubernetes_version/update_kubernetes_version.go index 6bd5325c21..75265150fd 100644 --- a/hack/kubernetes_version/update_kubernetes_version.go +++ b/hack/kubernetes_version/update_kubernetes_version.go @@ -17,70 +17,156 @@ limitations under the License. package main import ( - "fmt" + "context" + "flag" "io/ioutil" "os" "path/filepath" "regexp" "strings" + "time" "github.com/golang/glog" + + "github.com/google/go-github/v32/github" ) func main() { - if len(os.Args) == 1 { - fmt.Println("Usage: go run update_kubernetes_version.go ") - os.Exit(1) - } + // init glog: by default, all log statements write to files in a temporary directory, also + // flag.Parse must be called before any logging is done + flag.Parse() + _ = flag.Set("logtostderr", "true") - v := os.Args[1] - if !strings.HasPrefix(v, "v") { - v = "v" + v - } - - constantsFile := "../../pkg/minikube/constants/constants.go" - cf, err := ioutil.ReadFile(constantsFile) + // fetch respective current stable (vDefault as DefaultKubernetesVersion) and + // latest rc or beta (vDefault as NewestKubernetesVersion) Kubernetes GitHub Releases + vDefault, vNewest, err := fetchKubernetesReleases() if err != nil { - fmt.Println(err) - os.Exit(1) + glog.Errorf("Fetching current GitHub Releases failed: %v", err) + } + 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() +} + +// 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 { + return "", "", err + } + + for _, r := range rels { + // GetName returns the Name field if it's non-nil, zero value otherwise. + ver := r.GetName() + if ver == "" { + continue + } + + 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 } - info, err := os.Stat(constantsFile) - if err != nil { - fmt.Println(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) + 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 } - testData := "../../pkg/minikube/bootstrapper/bsutil/testdata" + // update testData just for the latest 'v..0' from vDefault + vDefaultMM := vDefault[:strings.LastIndex(vDefault, ".")] + testData := "../../pkg/minikube/bootstrapper/bsutil/testdata/" + vDefaultMM - err = filepath.Walk(testData, func(path string, info os.FileInfo, err error) error { + return filepath.Walk(testData, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if !strings.HasSuffix(path, "default.yaml") { return nil } - cf, err = ioutil.ReadFile(path) - if err != nil { - return err - } - re = regexp.MustCompile(`kubernetesVersion: .*`) - cf = []byte(re.ReplaceAllString(string(cf), "kubernetesVersion: "+v)) - return ioutil.WriteFile(path, cf, info.Mode()) + return replaceAllString(path, map[string]string{ + `kubernetesVersion: .*`: "kubernetesVersion: " + vDefaultMM + ".0", + }) }) - if err != nil { - glog.Errorf("Walk failed: %v", err) - } +} + +// 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 { + return err + } + + info, err := os.Stat(path) + if err != nil { + 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 } diff --git a/hack/preload-images/generate.go b/hack/preload-images/generate.go index ec3de2ece5..e1d6061d8b 100644 --- a/hack/preload-images/generate.go +++ b/hack/preload-images/generate.go @@ -39,6 +39,7 @@ import ( func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string) error { driver := kic.NewDriver(kic.Config{ + ClusterName: profile, KubernetesVersion: kubernetesVersion, ContainerRuntime: containerRuntime, OCIBinary: oci.Docker, diff --git a/images/logo/logo_white.svg b/images/logo/logo_white.svg index c932459ae6..1937fdc8b1 100644 --- a/images/logo/logo_white.svg +++ b/images/logo/logo_white.svg @@ -1,6 +1,6 @@ - - + + minikube Created with Sketch. diff --git a/pkg/addons/addons.go b/pkg/addons/addons.go index 8235e0cfd9..a7ca64a21e 100644 --- a/pkg/addons/addons.go +++ b/pkg/addons/addons.go @@ -324,7 +324,18 @@ func verifyAddonStatus(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 { @@ -394,16 +405,26 @@ func Start(wg *sync.WaitGroup, cc *config.ClusterConfig, toEnable map[string]boo 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) - 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 { + if a == "gcp-auth" { + deferredAddons = append(deferredAddons, a) + continue + } + awg.Add(1) go func(name string) { err := RunCallbacks(cc, name, "true") if err != nil { out.WarningT("Enabling '{{.name}}' returned an error: {{.error}}", out.V{"name": name, "error": err}) + } else { + enabledAddons = append(enabledAddons, name) } awg.Done() }(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) 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 { glog.Errorf("store failed: %v", err) } diff --git a/pkg/addons/config.go b/pkg/addons/config.go index 088698d91a..980915f407 100644 --- a/pkg/addons/config.go +++ b/pkg/addons/config.go @@ -169,7 +169,7 @@ var Addons = []*Addon{ { name: "gcp-auth", set: SetBool, - callbacks: []setFn{gcpauth.EnableOrDisable, enableOrDisableAddon, verifyGCPAuthAddon, gcpauth.DisplayAddonMessage}, + callbacks: []setFn{gcpauth.EnableOrDisable, enableOrDisableAddon, verifyGCPAuthAddon}, }, { name: "volumesnapshots", diff --git a/pkg/addons/gcpauth/enable.go b/pkg/addons/gcpauth/enable.go index 46c9ca0ec3..a394d481ef 100644 --- a/pkg/addons/gcpauth/enable.go +++ b/pkg/addons/gcpauth/enable.go @@ -60,7 +60,7 @@ func enableAddon(cfg *config.ClusterConfig) error { ctx := context.Background() creds, err := google.FindDefaultCredentials(ctx) 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") @@ -116,16 +116,3 @@ func disableAddon(cfg *config.ClusterConfig) error { 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 -} diff --git a/pkg/drivers/common.go b/pkg/drivers/common.go index 2fde2efde8..8c5c98bc73 100644 --- a/pkg/drivers/common.go +++ b/pkg/drivers/common.go @@ -29,6 +29,7 @@ import ( "github.com/docker/machine/libmachine/ssh" "github.com/golang/glog" "github.com/pkg/errors" + "k8s.io/minikube/pkg/util" ) // 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) } - 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 nil diff --git a/pkg/drivers/common_test.go b/pkg/drivers/common_test.go index cc250e03de..14cc631082 100644 --- a/pkg/drivers/common_test.go +++ b/pkg/drivers/common_test.go @@ -36,7 +36,7 @@ func Test_createDiskImage(t *testing.T) { diskPath := filepath.Join(tmpdir, "disk") sizeInMb := 100 - sizeInBytes := int64(sizeInMb) * 1000000 + sizeInBytes := int64(104857600) if err := createRawDiskImage(sshPath, diskPath, sizeInMb); err != nil { t.Errorf("createDiskImage() error = %v", err) } diff --git a/pkg/drivers/kic/kic.go b/pkg/drivers/kic/kic.go index 6c01be18ba..120d64a9b6 100644 --- a/pkg/drivers/kic/kic.go +++ b/pkg/drivers/kic/kic.go @@ -37,6 +37,8 @@ import ( "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" "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/util/retry" ) @@ -81,6 +83,17 @@ func (d *Driver) Create() error { 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 params.PortMappings = append(params.PortMappings, oci.PortMapping{ ListenAddress: oci.DefaultBindIPV4, @@ -289,6 +302,10 @@ func (d *Driver) Remove() error { 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) } + + 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 } @@ -403,7 +420,7 @@ func killAPIServerProc(runner command.Runner) error { pid, err := strconv.Atoi(rr.Stdout.String()) 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) - 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") } } diff --git a/pkg/drivers/kic/oci/cli_runner.go b/pkg/drivers/kic/oci/cli_runner.go index 9a5cabd567..7169e12bdb 100644 --- a/pkg/drivers/kic/oci/cli_runner.go +++ b/pkg/drivers/kic/oci/cli_runner.go @@ -144,9 +144,11 @@ func runCmd(cmd *exec.Cmd, warnSlow ...bool) (*RunResult, error) { } } - if exitError, ok := err.(*exec.ExitError); ok { - rr.ExitCode = exitError.ExitCode() + if ex, ok := err.(*exec.ExitError); ok { + glog.Warningf("%s returned with exit code %d", rr.Command(), ex.ExitCode()) + rr.ExitCode = ex.ExitCode() } + // Decrease log spam if elapsed > (1 * time.Second) { glog.Infof("Completed: %s: (%s)", rr.Command(), elapsed) diff --git a/pkg/drivers/kic/oci/errors.go b/pkg/drivers/kic/oci/errors.go index 8c30201f97..f8e65b7b1b 100644 --- a/pkg/drivers/kic/oci/errors.go +++ b/pkg/drivers/kic/oci/errors.go @@ -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 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. var ErrExitedUnexpectedly = errors.New("container exited unexpectedly") // ErrDaemonInfo is thrown when docker/podman info is failing or 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 func LogContainerDebug(ociBin string, name string) string { rr, err := containerInspect(ociBin, name) diff --git a/pkg/drivers/kic/oci/info.go b/pkg/drivers/kic/oci/info.go index e13d641a1e..e58a122967 100644 --- a/pkg/drivers/kic/oci/info.go +++ b/pkg/drivers/kic/oci/info.go @@ -22,20 +22,24 @@ import ( "strings" "time" + "github.com/golang/glog" "github.com/pkg/errors" ) // SysInfo Info represents common system Information between docker and podman that minikube cares type SysInfo struct { - CPUs int // CPUs is Number of CPUs - TotalMemory int64 // TotalMemory Total available ram - OSType string // container's OsType (windows or linux) - Swarm bool // Weather or not the docker swarm is active - StorageDriver string // the storage driver for the daemon (for example overlay2) + CPUs int // CPUs is Number of CPUs + TotalMemory int64 // TotalMemory Total available ram + OSType string // container's OsType (windows or linux) + Swarm bool // Weather or not the docker swarm is active + StorageDriver string // the storage driver for the daemon (for example overlay2) + Errors []string // any server issues } -var cachedSysInfo *SysInfo -var cachedSysInfoErr *error +var ( + cachedSysInfo *SysInfo + cachedSysInfoErr *error +) // CachedDaemonInfo will run and return a docker/podman info only once per minikube run time. to avoid performance func CachedDaemonInfo(ociBin string) (SysInfo, error) { @@ -58,7 +62,7 @@ func DaemonInfo(ociBin string) (SysInfo, error) { return *cachedSysInfo, err } 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 } @@ -163,6 +167,7 @@ type dockerSysInfo struct { SecurityOptions []string `json:"SecurityOptions"` ProductLicense string `json:"ProductLicense"` Warnings interface{} `json:"Warnings"` + ServerErrors []string ClientInfo struct { Debug bool `json:"Debug"` Plugins []interface{} `json:"Plugins"` @@ -245,6 +250,7 @@ func dockerSystemInfo() (dockerSysInfo, error) { return ds, errors.Wrapf(err, "unmarshal docker system info") } + glog.Infof("docker info: %+v", ds) return ds, nil } @@ -264,5 +270,6 @@ func podmanSystemInfo() (podmanSysInfo, error) { if err := json.Unmarshal([]byte(strings.TrimSpace(rawJSON)), &ps); err != nil { return ps, errors.Wrapf(err, "unmarshal podman system info") } + glog.Infof("podman info: %+v", ps) return ps, nil } diff --git a/pkg/drivers/kic/oci/network.go b/pkg/drivers/kic/oci/network.go index ca9e53bdb6..137063996a 100644 --- a/pkg/drivers/kic/oci/network.go +++ b/pkg/drivers/kic/oci/network.go @@ -31,17 +31,26 @@ import ( // RoutableHostIPFromInside returns the ip/dns of the host that container lives on // 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 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 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 +} diff --git a/pkg/drivers/kic/oci/oci.go b/pkg/drivers/kic/oci/oci.go index 878189e387..ac7c3ee87b 100644 --- a/pkg/drivers/kic/oci/oci.go +++ b/pkg/drivers/kic/oci/oci.go @@ -169,6 +169,11 @@ func CreateContainerNode(p CreateParams) error { virtualization = "podman" // VIRTUALIZATION_PODMAN } 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)) // ignore apparmore github actions docker: https://github.com/kubernetes/minikube/issues/7624 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 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 } diff --git a/pkg/drivers/kic/oci/types.go b/pkg/drivers/kic/oci/types.go index b2dad8de4a..b21da438ec 100644 --- a/pkg/drivers/kic/oci/types.go +++ b/pkg/drivers/kic/oci/types.go @@ -43,6 +43,7 @@ const ( // CreateParams are parameters needed to create a container type CreateParams struct { + ClusterName string // cluster(profile name) that this container belongs to Name string // used for container name and hostname Image string // container image to use to create the node. 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 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 + 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 diff --git a/pkg/drivers/kic/types.go b/pkg/drivers/kic/types.go index 5d138a0ea8..42ec88749a 100644 --- a/pkg/drivers/kic/types.go +++ b/pkg/drivers/kic/types.go @@ -24,9 +24,9 @@ import ( const ( // Version is the current version of kic - Version = "v0.0.12-snapshot3" + Version = "v0.0.13-snapshot1" // SHA of the kic base image - baseImageSHA = "1d687ba53e19dbe5fafe4cc18aa07f269ecc4b7b622f2251b5bf569ddb474e9b" + baseImageSHA = "4d43acbd0050148d4bc399931f1b15253b5e73815b63a67b8ab4a5c9e523403f" ) var ( @@ -48,6 +48,7 @@ var ( // Config is configuration for the kic driver used by registry type Config struct { + ClusterName string // The cluster the container belongs to MachineName string // maps to the container name being created CPU int // Number of CPU cores assigned to the container Memory int // max memory in MB diff --git a/pkg/drivers/kvm/domain.go b/pkg/drivers/kvm/domain.go index 2d8a18d5fa..3a69cc0b93 100644 --- a/pkg/drivers/kvm/domain.go +++ b/pkg/drivers/kvm/domain.go @@ -31,8 +31,8 @@ import ( const domainTmpl = ` - {{.MachineName}} - {{.Memory}} + {{.MachineName}} + {{.Memory}} {{.CPU}} diff --git a/pkg/minikube/cluster/ip.go b/pkg/minikube/cluster/ip.go index f853848399..caf34e2bb2 100644 --- a/pkg/minikube/cluster/ip.go +++ b/pkg/minikube/cluster/ip.go @@ -34,12 +34,12 @@ import ( ) // 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 { case driver.Docker: - return oci.RoutableHostIPFromInside(oci.Docker, host.Name) + return oci.RoutableHostIPFromInside(oci.Docker, clusterName, host.Name) case driver.Podman: - return oci.RoutableHostIPFromInside(oci.Podman, host.Name) + return oci.RoutableHostIPFromInside(oci.Podman, clusterName, host.Name) case driver.KVM2: return net.ParseIP("192.168.39.1"), nil case driver.HyperV: @@ -49,6 +49,7 @@ func HostIP(host *host.Host) (net.IP, error) { for i := 0; i < v.NumField(); i++ { if v.Type().Field(i).Name == "VSwitch" { hypervVirtualSwitch = v.Field(i).Interface().(string) + break } } @@ -59,6 +60,7 @@ func HostIP(host *host.Host) (net.IP, error) { if err != nil { return []byte{}, errors.Wrap(err, fmt.Sprintf("ip for interface (%s)", hypervVirtualSwitch)) } + return ip, nil case driver.VirtualBox: 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+)`) ip := re.FindStringSubmatch(string(ipList))[1] + return net.ParseIP(ip), nil case driver.Parallels: 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") } ip := ipMatch[1] + return net.ParseIP(ip), nil case driver.HyperKit: 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 func getIPForInterface(name string) (net.IP, error) { + glog.Infof("getIPForInterface: searching for %q", name) ints, err := net.Interfaces() if err != nil { return nil, err @@ -143,19 +148,25 @@ func getIPForInterface(name string) (net.IP, error) { var i net.Interface 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 + break } + glog.Infof("%q does not match prefix %q", in.Name, name) } // Didn't find prefix, let's try any substring if i.Name == "" { 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 + 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) } - glog.Infof("Found hyperv interface: %+v\n", i) + glog.Infof("Found interface: %+v\n", i) addrs, _ := i.Addrs() for _, a := range addrs { + glog.Infof("interface addr: %+v", a) if ipnet, ok := a.(*net.IPNet); ok { if ip := ipnet.IP.To4(); 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) } diff --git a/pkg/minikube/config/config.go b/pkg/minikube/config/config.go index 93e9332dcc..5fd296630c 100644 --- a/pkg/minikube/config/config.go +++ b/pkg/minikube/config/config.go @@ -80,6 +80,24 @@ func IsNotExist(err error) bool { 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 type MinikubeConfig map[string]interface{} @@ -184,6 +202,9 @@ func (c *simpleConfigLoader) LoadConfigFromFile(profileName string, miniHome ... data, err := ioutil.ReadFile(path) if err != nil { + if os.IsPermission(err) { + return nil, &ErrPermissionDenied{err.Error()} + } return nil, errors.Wrap(err, "read") } diff --git a/pkg/minikube/driver/driver.go b/pkg/minikube/driver/driver.go index 791b3d0bd3..2002ea3afd 100644 --- a/pkg/minikube/driver/driver.go +++ b/pkg/minikube/driver/driver.go @@ -21,6 +21,7 @@ import ( "os" "runtime" "sort" + "strconv" "strings" "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) } + +// 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 +} diff --git a/pkg/minikube/driver/driver_test.go b/pkg/minikube/driver/driver_test.go index b6afd6a62c..953ff53691 100644 --- a/pkg/minikube/driver/driver_test.go +++ b/pkg/minikube/driver/driver_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "k8s.io/minikube/pkg/minikube/config" "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) + } + + } +} diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index 5d00ecbaa7..4ae7b08dd7 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -42,6 +42,7 @@ import ( var exclude = []string{ "{{.error}}", "{{.url}}", + " {{.url}}", "{{.msg}}: {{.err}}", "{{.key}}={{.value}}", "opt {{.docker_option}}", @@ -50,6 +51,7 @@ var exclude = []string{ "\\n", "==\u003e {{.name}} \u003c==", "- {{.profile}}", + " - {{.profile}}", } // 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 stringToTranslate := s[1 : len(s)-1] - // Trim whitespace - stringToTranslate = strings.TrimSpace(stringToTranslate) - // Don't translate integers if _, err := strconv.Atoi(stringToTranslate); err == nil { return "" diff --git a/pkg/minikube/machine/advice.go b/pkg/minikube/machine/advice.go index 268ab56788..495d55a1ef 100644 --- a/pkg/minikube/machine/advice.go +++ b/pkg/minikube/machine/advice.go @@ -40,27 +40,27 @@ func MaybeDisplayAdvice(err error, driver string) { 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}) if driver == oci.Docker || driver == oci.Podman { - out.T(style.Empty, ` - - Prune unused {{.driver_name}} images, volumes, networks and abandoned containers. + out.String("\n\t") + 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, ` - - Restart your {{.driver_name}} service`, out.V{"driver_name": driver}) + out.String("\n\t") + out.T(style.Empty, `- Restart your {{.driver_name}} service`, out.V{"driver_name": driver}) if runtime.GOOS != "linux" { - out.T(style.Empty, ` - - Ensure your {{.driver_name}} daemon has access to enough CPU/memory resources. `, out.V{"driver_name": driver}) + out.String("\n\t") + 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 { - out.T(style.Empty, ` - - Docs https://docs.docker.com/docker-for-mac/#resources`, out.V{"driver_name": driver}) + out.String("\n\t") + 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 { - out.T(style.Empty, ` - - Docs https://docs.docker.com/docker-for-windows/#resources`, out.V{"driver_name": driver}) + out.String("\n\t") + out.T(style.Empty, `- Docs https://docs.docker.com/docker-for-windows/#resources`, out.V{"driver_name": driver}) } } - out.T(style.Empty, ` - - Delete and recreate minikube cluster + out.String("\n\t") + out.T(style.Empty, `- Delete and recreate minikube cluster minikube delete 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 diff --git a/pkg/minikube/machine/delete.go b/pkg/minikube/machine/delete.go index f4bfa83f47..e4ad04b058 100644 --- a/pkg/minikube/machine/delete.go +++ b/pkg/minikube/machine/delete.go @@ -46,7 +46,7 @@ func deleteOrphanedKIC(ociBin string, name string) { glog.Infof("couldn't inspect container %q before deleting: %v", name, err) 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) defer cancel() diff --git a/pkg/minikube/machine/info.go b/pkg/minikube/machine/info.go index 99bf55982d..4305a5a143 100644 --- a/pkg/minikube/machine/info.go +++ b/pkg/minikube/machine/info.go @@ -29,6 +29,7 @@ import ( "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/out/register" "k8s.io/minikube/pkg/minikube/style" + "k8s.io/minikube/pkg/util" ) // HostInfo holds information on the user's machine @@ -38,10 +39,6 @@ type HostInfo struct { DiskSize int64 } -func megs(bytes uint64) int64 { - return int64(bytes / 1024 / 1024) -} - // CachedHostInfo returns system information such as memory,CPU, DiskSize func CachedHostInfo() (*HostInfo, error, error, error) { var cpuErr, memErr, diskErr error @@ -61,8 +58,8 @@ func CachedHostInfo() (*HostInfo, error, error, error) { var info HostInfo info.CPUs = len(i) - info.Memory = megs(v.Total) - info.DiskSize = megs(d.Total) + info.Memory = util.ConvertUnsignedBytesToMB(v.Total) + info.DiskSize = util.ConvertUnsignedBytesToMB(d.Total) return &info, cpuErr, memErr, diskErr } diff --git a/pkg/minikube/node/cache.go b/pkg/minikube/node/cache.go index bcb3b7807a..859c6456b0 100644 --- a/pkg/minikube/node/cache.go +++ b/pkg/minikube/node/cache.go @@ -127,7 +127,7 @@ func beginDownloadKicBaseImage(g *errgroup.Group, cc *config.ClusterConfig, down // If we end up using a fallback image, notify the user defer func() { 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 } }() @@ -136,7 +136,7 @@ func beginDownloadKicBaseImage(g *errgroup.Group, cc *config.ClusterConfig, down glog.Infof("successfully loaded %s from cached tarball", img) // 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 - finalImg = image.Tag(img) + finalImg = img return nil } glog.Infof("Downloading %s to local daemon", img) diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go index 2a40e806f9..c00aa6cadc 100644 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -94,7 +94,7 @@ func Start(starter Starter, apiServer bool) (*kubeconfig.Settings, error) { showVersionInfo(starter.Node.KubernetesVersion, cr) // 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 { glog.Errorf("Unable to get host IP: %v", err) } 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 { addr, err := apiServerURL(*h, *cc, *n) 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 { diff --git a/pkg/minikube/out/register/register.go b/pkg/minikube/out/register/register.go index d4ff06af5e..22cbb5dcfe 100644 --- a/pkg/minikube/out/register/register.go +++ b/pkg/minikube/out/register/register.go @@ -62,7 +62,7 @@ func init() { Reg = Register{ // Expected step orders, organized by the initial step seen steps: map[RegStep][]RegStep{ - InitialSetup: []RegStep{ + InitialSetup: { InitialSetup, SelectingDriver, DownloadingArtifacts, @@ -78,10 +78,10 @@ func init() { Done, }, - Stopping: []RegStep{Stopping, Done}, - Pausing: []RegStep{Pausing, Done}, - Unpausing: []RegStep{Unpausing, Done}, - Deleting: []RegStep{Deleting, Stopping, Deleting, Done}, + Stopping: {Stopping, Done}, + Pausing: {Pausing, Done}, + Unpausing: {Unpausing, Done}, + Deleting: {Deleting, Stopping, Deleting, Done}, }, } } diff --git a/pkg/minikube/perf/logs_test.go b/pkg/minikube/perf/logs_test.go index b62e0cb295..0fbdf35bfb 100644 --- a/pkg/minikube/perf/logs_test.go +++ b/pkg/minikube/perf/logs_test.go @@ -38,7 +38,8 @@ func TestTimeCommandLogs(t *testing.T) { if !ok { 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) } } diff --git a/pkg/minikube/reason/known_issues.go b/pkg/minikube/reason/known_issues.go index 49ed0417dd..17347661b4 100644 --- a/pkg/minikube/reason/known_issues.go +++ b/pkg/minikube/reason/known_issues.go @@ -202,12 +202,7 @@ var hostIssues = []match{ GOOS: []string{"linux"}, }, { - Kind: Kind{ - 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}, - }, + Kind: HostHomePermission, Regexp: re(`/.minikube/.*: permission denied`), }, } diff --git a/pkg/minikube/reason/reason.go b/pkg/minikube/reason/reason.go index ee9a3faf6b..497f54cfa7 100644 --- a/pkg/minikube/reason/reason.go +++ b/pkg/minikube/reason/reason.go @@ -188,10 +188,17 @@ var ( RsrcInsufficientStorage = Kind{ID: "RSRC_INSUFFICIENT_STORAGE", ExitCode: ExInsufficientStorage, Style: style.UnmetRequirement} - HostHomeMkdir = Kind{ID: "HOST_HOME_MKDIR", ExitCode: ExHostPermission} - HostHomeChown = Kind{ID: "HOST_HOME_CHOWN", ExitCode: ExHostPermission} - HostBrowser = Kind{ID: "HOST_BROWSER", ExitCode: ExHostError} - HostConfigLoad = Kind{ID: "HOST_CONFIG_LOAD", ExitCode: ExHostConfig} + HostHomeMkdir = Kind{ID: "HOST_HOME_MKDIR", ExitCode: ExHostPermission} + HostHomeChown = Kind{ID: "HOST_HOME_CHOWN", ExitCode: ExHostPermission} + HostBrowser = Kind{ID: "HOST_BROWSER", ExitCode: ExHostError} + 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} HostDelCache = Kind{ID: "HOST_DEL_CACHE", ExitCode: ExHostError} HostKillMountProc = Kind{ID: "HOST_KILL_MOUNT_PROC", ExitCode: ExHostError} @@ -207,7 +214,13 @@ var ( ProviderNotFound = Kind{ID: "PROVIDER_NOT_FOUND", ExitCode: ExProviderNotFound} 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} DrvUnsupportedMulti = Kind{ID: "DRV_UNSUPPORTED_MULTINODE", ExitCode: ExDriverConflict} DrvUnsupportedOS = Kind{ID: "DRV_UNSUPPORTED_OS", ExitCode: ExDriverUnsupported} diff --git a/pkg/minikube/registry/drvs/docker/docker.go b/pkg/minikube/registry/drvs/docker/docker.go index ed2716a2df..98d961e1d2 100644 --- a/pkg/minikube/registry/drvs/docker/docker.go +++ b/pkg/minikube/registry/drvs/docker/docker.go @@ -27,6 +27,7 @@ import ( "github.com/docker/machine/libmachine/drivers" "github.com/golang/glog" + "github.com/pkg/errors" "k8s.io/minikube/pkg/drivers/kic" "k8s.io/minikube/pkg/drivers/kic/oci" "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{ + ClusterName: cc.Name, MachineName: driver.MachineName(cc, n), StorePath: localpath.MiniPath(), ImageDigest: cc.KicBaseImage, @@ -86,34 +88,41 @@ func status() registry.State { ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second) defer cancel() - // Quickly returns an error code if server is not running cmd := exec.CommandContext(ctx, oci.Docker, "version", "--format", "{{.Server.Os}}-{{.Server.Version}}") o, err := cmd.Output() - output := string(o) - 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 { + if ctx.Err() == context.DeadlineExceeded { + err = errors.Wrapf(err, "deadline exceeded running %q", strings.Join(cmd.Args, " ")) + } - } - if err == nil { - glog.Infof("docker version: %s", output) - return checkNeedsImprovement() - } + glog.Warningf("docker version returned error: %v", err) - glog.Warningf("docker returned error: %v", err) + if exitErr, ok := err.(*exec.ExitError); ok { + stderr := strings.TrimSpace(string(exitErr.Stderr)) + newErr := fmt.Errorf(`%q %v: %s`, strings.Join(cmd.Args, " "), exitErr, stderr) + + return suggestFix(stderr, newErr) + } - // Basic timeout - if ctx.Err() == context.DeadlineExceeded { - glog.Warningf("%q timed out. ", strings.Join(cmd.Args, " ")) return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Restart the Docker service", Doc: docURL} } - if exitErr, ok := err.(*exec.ExitError); ok { - stderr := strings.TrimSpace(string(exitErr.Stderr)) - newErr := fmt.Errorf(`%q %v: %s`, strings.Join(cmd.Args, " "), exitErr, stderr) - return suggestFix(stderr, newErr) + 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"} } - return registry.State{Error: err, Installed: true, Healthy: false, Doc: docURL} + 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 @@ -121,6 +130,7 @@ func checkNeedsImprovement() registry.State { if runtime.GOOS == "linux" { return checkOverlayMod() } + return registry.State{Installed: true, Healthy: true} } @@ -128,15 +138,18 @@ func checkNeedsImprovement() registry.State { func checkOverlayMod() registry.State { if _, err := os.Stat("/sys/module/overlay"); err == nil { glog.Info("overlay module found") + return registry.State{Installed: true, Healthy: true} } if _, err := os.Stat("/sys/module/overlay2"); err == nil { glog.Info("overlay2 module found") + return registry.State{Installed: true, Healthy: true} } 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'"} } @@ -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"} } - 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} } // 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} } + +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") +} diff --git a/pkg/minikube/registry/drvs/podman/podman.go b/pkg/minikube/registry/drvs/podman/podman.go index 166fd9e6d5..fdf912f5e2 100644 --- a/pkg/minikube/registry/drvs/podman/podman.go +++ b/pkg/minikube/registry/drvs/podman/podman.go @@ -73,6 +73,7 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { } return kic.NewDriver(kic.Config{ + ClusterName: cc.Name, MachineName: driver.MachineName(cc, n), StorePath: localpath.MiniPath(), ImageDigest: strings.Split(cc.KicBaseImage, "@")[0], // for podman does not support docker images references with both a tag and digest. diff --git a/pkg/perf/monitor/constants.go b/pkg/perf/monitor/constants.go new file mode 100644 index 0000000000..be4a0011ab --- /dev/null +++ b/pkg/perf/monitor/constants.go @@ -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" +) diff --git a/pkg/perf/monitor/execute.go b/pkg/perf/monitor/execute.go new file mode 100644 index 0000000000..543ed0114c --- /dev/null +++ b/pkg/perf/monitor/execute.go @@ -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") +} diff --git a/pkg/perf/monitor/github.go b/pkg/perf/monitor/github.go new file mode 100644 index 0000000000..eb3146136e --- /dev/null +++ b/pkg/perf/monitor/github.go @@ -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 +} diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 6a5c3bf0f6..518c1d7966 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -24,7 +24,7 @@ import ( "strconv" "github.com/blang/semver" - "github.com/docker/go-units" + units "github.com/docker/go-units" "github.com/pkg/errors" ) @@ -47,6 +47,18 @@ func CalculateSizeInMB(humanReadableSize string) (int, error) { 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 func GetBinaryDownloadURL(version, platform string) string { switch platform { diff --git a/site/content/en/docs/commands/addons.md b/site/content/en/docs/commands/addons.md index b35589cfe4..dd8af6140f 100644 --- a/site/content/en/docs/commands/addons.md +++ b/site/content/en/docs/commands/addons.md @@ -39,11 +39,11 @@ minikube addons SUBCOMMAND [flags] ## minikube addons configure -Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list +Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list ### Synopsis -Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list +Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list ``` minikube addons configure ADDON_NAME [flags] diff --git a/site/content/en/docs/commands/completion.md b/site/content/en/docs/commands/completion.md index 09f118c9f0..dbe36b99d3 100644 --- a/site/content/en/docs/commands/completion.md +++ b/site/content/en/docs/commands/completion.md @@ -11,8 +11,7 @@ Generate command completion for a shell ### 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: OS X: diff --git a/site/content/en/docs/commands/start.md b/site/content/en/docs/commands/start.md index 4897e40f8d..87538fb59c 100644 --- a/site/content/en/docs/commands/start.md +++ b/site/content/en/docs/commands/start.md @@ -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-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) - --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) --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") @@ -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. --install-addons If set, install addons. Defaults to true. (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. --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 diff --git a/site/content/en/docs/handbook/addons/gcp-auth.md b/site/content/en/docs/handbook/addons/gcp-auth.md index 14194909e9..19aabd3920 100644 --- a/site/content/en/docs/handbook/addons/gcp-auth.md +++ b/site/content/en/docs/handbook/addons/gcp-auth.md @@ -5,7 +5,7 @@ weight: 1 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: ``` diff --git a/site/content/en/docs/handbook/vpn_and_proxy.md b/site/content/en/docs/handbook/vpn_and_proxy.md index 3d430b10b4..bcd92ee5c8 100644 --- a/site/content/en/docs/handbook/vpn_and_proxy.md +++ b/site/content/en/docs/handbook/vpn_and_proxy.md @@ -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.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` 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)). diff --git a/translations/strings.txt b/translations/strings.txt index c80809c9d9..6abccd32da 100644 --- a/translations/strings.txt +++ b/translations/strings.txt @@ -11,7 +11,7 @@ "- Docs https://docs.docker.com/docker-for-mac/#resources": "", "- Docs https://docs.docker.com/docker-for-windows/#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": "", "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.": "", @@ -45,7 +45,7 @@ "Basic Commands:": "", "Because you are using a Docker driver on {{.operating_system}}, the terminal needs to be open to run it.": "", "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)": "", "Cannot find directory {{.path}} for mount": "", "Cannot use both --output and --format options": "", @@ -68,7 +68,7 @@ "Confirm that you have a working internet connection and that your VM has not run out of resources by using: 'minikube logs'": "", "Confirm that you have supplied the correct value to --hyperv-virtual-switch using the 'Get-VMSwitch' command": "", "Connect to LoadBalancer services": "", - "Consider creating a cluster with larger memory size using `minikube start --memory SIZE_MB`": "", + "Consider creating a cluster with larger memory size using `minikube start --memory SIZE_MB` ": "", "Consider increasing Docker Desktop's memory size.": "", "Could not determine a Google Cloud project, which might be ok.": "", "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.": "", @@ -78,6 +78,7 @@ "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, Disk={{.disk_size}}MB) ...": "", + "Current context is \"{{.context}}\"": "", "DEPRECATED, use `driver` instead.": "", "DEPRECATED: Replaced by --cni=bridge": "", "Default group id used for the mount": "", @@ -91,7 +92,7 @@ "Deleting node {{.name}} from cluster {{.cluster}}": "", "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)": "", "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", - "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list": "", + "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list ": "", "Disables the filesystem mounts provided by the hypervisors": "", "Disk size allocated to the minikube VM (format: \u003cnumber\u003e[\u003cunit\u003e], where unit = b, k, m or g).": "", "Display dashboard URL instead of opening a browser": "", @@ -102,10 +103,9 @@ "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 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 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}}": "", "Documentation: {{.url}}": "", "Done! kubectl is now configured to use \"{{.name}}\" by default": "", @@ -127,7 +127,7 @@ "Enable or disable a minikube addon": "", "Enable proxy for NAT DNS requests (virtualbox driver only)": "", "Enabled addons: {{.addons}}": "", - "Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list": "", + "Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list ": "", "Enabling '{{.name}}' returned an error: {{.error}}": "", "Enabling dashboard ...": "", "Ensure that CRI-O is installed and healthy: Run 'sudo systemctl start crio' and 'journalctl -u crio'. Alternatively, use --container-runtime=docker": "", @@ -161,6 +161,7 @@ "Error starting cluster": "", "Error starting mount": "", "Error while setting kubectl current context : {{.error}}": "", + "Error while setting kubectl current context: {{.error}}": "", "Error writing mount pid": "", "Examples": "", "Executing \"{{.command}}\" took an unusually long time: {{.duration}}": "", @@ -180,7 +181,6 @@ "Failed to delete images": "", "Failed to delete images from config": "", "Failed to enable container runtime": "", - "Failed to get API Server URL": "", "Failed to get bootstrapper": "", "Failed to get command runner": "", "Failed to get image map": "", @@ -208,7 +208,7 @@ "Force minikube to perform possibly dangerous operations": "", "Format to print stdout in. Options include: [text,json]": "", "Found network options:": "", - "Found {{.number}} invalid profile(s) !": "", + "Found {{.number}} invalid profile(s) ! ": "", "Generate command completion for a shell": "", "Generate unable to parse disk size '{{.diskSize}}': {{.error}}": "", "Generate unable to parse memory '{{.memory}}': {{.error}}": "", @@ -232,7 +232,7 @@ "If set, install addons. Defaults to true.": "", "If set, pause all namespaces": "", "If set, unpause all namespaces": "", - "If the above advice does not help, please let us know:": "", + "If the above advice does not help, please let us know: ": "", "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.": "", "If true, only download and cache files for later use - don't install or start anything.": "", "If true, the added node will be marked for work. Defaults to true.": "", @@ -277,7 +277,7 @@ "Mounts the specified directory into minikube.": "", "Multi-node clusters are currently experimental and might exhibit unintended behavior.": "", "Multiple errors deleting profiles": "", - "Multiple minikube profiles were found -": "", + "Multiple minikube profiles were found - ": "", "NIC Type used for host only network. One of Am79C970A, Am79C973, 82540EM, 82543GC, 82545EM, or virtio (virtualbox driver only)": "", "NIC Type used for nat network. One of Am79C970A, Am79C973, 82540EM, 82543GC, 82545EM, or virtio (virtualbox driver only)": "", "NOTE: This process must stay alive for the mount to be accessible ...": "", @@ -299,21 +299,21 @@ "One of 'yaml' or 'json'.": "", "Only alphanumeric and dashes '-' are permitted. Minimum 1 character, starting with alphanumeric.": "", "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 service {{.namespace_name}}/{{.service_name}} in default browser...": "", "Opening {{.url}} in your default browser...": "", - "Opens the addon w/ADDON_NAME within minikube (example: minikube addons open dashboard). For a list of available addons use: minikube addons list": "", + "Opens the addon w/ADDON_NAME within minikube (example: minikube addons open dashboard). For a list of available addons use: minikube addons list ": "", "Operations on nodes": "", "Options: {{.options}}": "", "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": "", "Paused {{.count}} containers": "", "Paused {{.count}} containers in: {{.namespaces}}": "", - "Pausing node {{.name}} ...": "", + "Pausing node {{.name}} ... ": "", "Permissions: {{.octalMode}} ({{.writtenMode}})": "", - "Please create a cluster with bigger disk size: `minikube start --disk SIZE_MB`": "", + "Please create a cluster with bigger disk size: `minikube start --disk SIZE_MB` ": "", "Please either authenticate to the registry or use --base-image flag to use a different registry.": "", "Please enter a value:": "", "Please free up disk or prune images.": "", @@ -321,11 +321,11 @@ "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 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 podman-env, To ensure your environment variables have updated ports:\n\n\t'minikube -p {{.profile_name}} podman-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'\n\n\t": "", "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 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": "", "PowerShell is running in constrained mode, which is incompatible with Hyper-V scripting.": "", "Powering off \"{{.profile_name}}\" via SSH ...": "", @@ -400,7 +400,7 @@ "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.": "", "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, completion support is not yet implemented for {{.name}}": "", "Sorry, please set the --output flag to one of the following valid options: [text,json]": "", @@ -555,12 +555,12 @@ "Unable to safely downgrade existing Kubernetes v{{.old}} cluster to v{{.new}}": "", "Unable to stop VM": "", "Unable to update {{.driver}} driver: {{.error}}": "", - "Unfortunately, could not download the base image {{.image_name}}": "", + "Unfortunately, could not download the base image {{.image_name}} ": "", "Uninstalling Kubernetes {{.kubernetes_version}} using {{.bootstrapper_name}} ...": "", "Unmounting {{.path}} ...": "", "Unpaused {{.count}} containers": "", "Unpaused {{.count}} containers in: {{.namespaces}}": "", - "Unpausing node {{.name}} ...": "", + "Unpausing node {{.name}} ... ": "", "Unset the KUBECONFIG environment variable, or verify that it does not point to an empty or otherwise invalid path": "", "Unset variables instead of setting them": "", "Update kubeconfig in case of an IP or port change": "", @@ -583,7 +583,7 @@ "Use native Golang SSH client (default true). Set to 'false' to use the command line 'ssh' command when accessing the docker machine. Useful for the machine drivers when they will not start with 'Waiting for SSH'.": "", "User ID: {{.userID}}": "", "Userspace file server is shutdown": "", - "Userspace file server:": "", + "Userspace file server: ": "", "Using image repository {{.name}}": "", "Using podman 2 is not supported yet. your version is \"{{.currentVersion}}\". minikube might not work. use at your own risk.": "", "Using the '{{.runtime}}' runtime with the 'none' driver is an untested configuration!": "", @@ -608,7 +608,7 @@ "Where to root the NFS Shares, defaults to /nfsshares (hyperkit driver only)": "", "Whether to use external switch over Default Switch if virtual switch not explicitly specified. (hyperv driver only)": "", "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP ({{.ip_address}}).": "", - "You can delete them using the following command(s):": "", + "You can delete them using the following command(s): ": "", "You can force an unsupported Kubernetes version via the --force flag": "", "You cannot change the CPUs for an existing minikube cluster. Please first delete the cluster.": "", "You cannot change the Disk size for an exiting minikube cluster. Please first delete the cluster.": "", @@ -622,13 +622,13 @@ "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 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 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\"": "", "bash completion failed": "", "call with cleanup=true to remove old tunnels": "", - "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields:\\n\\n": "", + "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields: \\n\\n": "", "config view failed": "", "dashboard service is not running: {{.error}}": "", "deleting node": "", @@ -660,14 +660,14 @@ "kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "", "kubectl proxy": "", "libmachine failed": "", - "list displays all valid default settings for PROPERTY_NAME\nAcceptable fields:\\n\\n": "", + "list displays all valid default settings for PROPERTY_NAME\nAcceptable fields: \\n\\n": "", "logdir set failed": "", "max time to wait per Kubernetes or host to be healthy.": "", "minikube addons list --output OUTPUT. json, list": "", "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 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 provisions and manages local Kubernetes clusters optimized for development workflows.": "", "minikube quickly sets up a local Kubernetes cluster": "", @@ -715,6 +715,7 @@ "version yaml failure": "", "zsh completion failed": "", "{{ .name }}: {{ .rejection }}": "", + "{{.Driver}} is currently using the {{.StorageDriver}} storage driver, consider switching to overlay2 for better performance": "", "{{.count}} nodes stopped.": "", "{{.driver_name}} \"{{.cluster}}\" {{.machine_type}} is missing, will recreate.": "", "{{.driver_name}} couldn't proceed because {{.driver_name}} service is not healthy.": "", @@ -725,6 +726,8 @@ "{{.name}} has no available configuration options": "", "{{.name}} is already running": "", "{{.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}}": "", "{{.path}} is version {{.client_version}}, which may have incompatibilites with Kubernetes {{.cluster_version}}.": "", "{{.prefix}}minikube {{.version}} on {{.platform}}": "",