commit
be196bfe9d
|
@ -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
|
||||
|
|
26
CHANGELOG.md
26
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
|
||||
|
|
22
Makefile
22
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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
||||
if len(validProfiles) == 0 || err != nil {
|
||||
exit.Message(reason.Usage, "No minikube profile was found. You can create one using `minikube start`.")
|
||||
table.AppendBulk(ps)
|
||||
table.Render()
|
||||
}
|
||||
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)
|
||||
|
||||
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})
|
||||
}
|
||||
validData = append(validData, []string{p.Name, p.Config.Driver, p.Config.KubernetesConfig.ContainerRuntime, cp.IP, strconv.Itoa(cp.Port), p.Config.KubernetesConfig.KubernetesVersion, p.Status})
|
||||
return data
|
||||
}
|
||||
|
||||
table.AppendBulk(validData)
|
||||
table.Render()
|
||||
func warnInvalidProfiles(invalidProfiles []*config.Profile) {
|
||||
if invalidProfiles == nil {
|
||||
return
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
glog.Warningf("error loading profiles: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var printProfilesJSON = func() {
|
||||
api, err := machine.NewAPIClient()
|
||||
if err != nil {
|
||||
glog.Errorf("failed to get machine api client %v", err)
|
||||
}
|
||||
defer api.Close()
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Turn on Source Address Verification in all interfaces to
|
||||
# prevent some spoofing attacks.
|
||||
net.ipv4.conf.default.rp_filter=1
|
||||
net.ipv4.conf.all.rp_filter=1
|
|
@ -1,44 +1,125 @@
|
|||
# Copyright 2018 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# kind node base image
|
||||
#
|
||||
# For systemd + docker configuration used below, see the following references:
|
||||
# https://www.freedesktop.org/wiki/Software/systemd/ContainerInterface/
|
||||
|
||||
# start from ubuntu 20.04, this image is reasonably small as a starting point
|
||||
# for a kubernetes node image, it doesn't contain much we don't need
|
||||
FROM ubuntu:focal-20200423
|
||||
|
||||
# copy in static files (configs, scripts)
|
||||
COPY 10-network-security.conf /etc/sysctl.d/10-network-security.conf
|
||||
COPY clean-install /usr/local/bin/clean-install
|
||||
COPY entrypoint /usr/local/bin/entrypoint
|
||||
|
||||
# Install dependencies, first from apt, then from release tarballs.
|
||||
# NOTE: we use one RUN to minimize layers.
|
||||
#
|
||||
# First we must ensure that our util scripts are executable.
|
||||
#
|
||||
# The base image already has: ssh, apt, snapd, but we need to install more packages.
|
||||
# Packages installed are broken down into (each on a line):
|
||||
# - packages needed to run services (systemd)
|
||||
# - packages needed for kubernetes components
|
||||
# - packages needed by the container runtime
|
||||
# - misc packages kind uses itself
|
||||
# After installing packages we cleanup by:
|
||||
# - removing unwanted systemd services
|
||||
# - disabling kmsg in journald (these log entries would be confusing)
|
||||
#
|
||||
# Next we ensure the /etc/kubernetes/manifests directory exists. Normally
|
||||
# a kubeadm debain / rpm package would ensure that this exists but we install
|
||||
# freshly built binaries directly when we build the node image.
|
||||
#
|
||||
# Finally we adjust tempfiles cleanup to be 1 minute after "boot" instead of 15m
|
||||
# This is plenty after we've done initial setup for a node, but before we are
|
||||
# likely to try to export logs etc.
|
||||
RUN echo "Ensuring scripts are executable ..." \
|
||||
&& chmod +x /usr/local/bin/clean-install /usr/local/bin/entrypoint \
|
||||
&& echo "Installing Packages ..." \
|
||||
&& DEBIAN_FRONTEND=noninteractive clean-install \
|
||||
systemd \
|
||||
conntrack iptables iproute2 ethtool socat util-linux mount ebtables udev kmod \
|
||||
libseccomp2 \
|
||||
bash ca-certificates curl rsync \
|
||||
&& find /lib/systemd/system/sysinit.target.wants/ -name "systemd-tmpfiles-setup.service" -delete \
|
||||
&& rm -f /lib/systemd/system/multi-user.target.wants/* \
|
||||
&& rm -f /etc/systemd/system/*.wants/* \
|
||||
&& rm -f /lib/systemd/system/local-fs.target.wants/* \
|
||||
&& rm -f /lib/systemd/system/sockets.target.wants/*udev* \
|
||||
&& rm -f /lib/systemd/system/sockets.target.wants/*initctl* \
|
||||
&& rm -f /lib/systemd/system/basic.target.wants/* \
|
||||
&& echo "ReadKMsg=no" >> /etc/systemd/journald.conf \
|
||||
&& ln -s "$(which systemd)" /sbin/init \
|
||||
&& echo "Ensuring /etc/kubernetes/manifests" \
|
||||
&& mkdir -p /etc/kubernetes/manifests \
|
||||
&& echo "Adjusting systemd-tmpfiles timer" \
|
||||
&& sed -i /usr/lib/systemd/system/systemd-tmpfiles-clean.timer -e 's#OnBootSec=.*#OnBootSec=1min#' \
|
||||
&& echo "Modifying /etc/nsswitch.conf to prefer hosts" \
|
||||
&& sed -i /etc/nsswitch.conf -re 's#^(hosts:\s*).*#\1dns files#'
|
||||
|
||||
# tell systemd that it is in docker (it will check for the container env)
|
||||
# https://www.freedesktop.org/wiki/Software/systemd/ContainerInterface/
|
||||
ENV container docker
|
||||
# systemd exits on SIGRTMIN+3, not SIGTERM (which re-executes it)
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1201657
|
||||
STOPSIGNAL SIGRTMIN+3
|
||||
# NOTE: this is *only* for documentation, the entrypoint is overridden later
|
||||
ENTRYPOINT [ "/usr/local/bin/entrypoint", "/sbin/init" ]
|
||||
|
||||
ARG COMMIT_SHA
|
||||
# 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/* \
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright 2017 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# A script encapsulating a common Dockerimage pattern for installing packages
|
||||
# and then cleaning up the unnecessary install artifacts.
|
||||
# e.g. clean-install iptables ebtables conntrack
|
||||
|
||||
set -o errexit
|
||||
|
||||
if [ $# = 0 ]; then
|
||||
echo >&2 "No packages specified"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends "$@"
|
||||
apt-get clean -y
|
||||
rm -rf \
|
||||
/var/cache/debconf/* \
|
||||
/var/lib/apt/lists/* \
|
||||
/var/log/* \
|
||||
/tmp/* \
|
||||
/var/tmp/* \
|
||||
/usr/share/doc/* \
|
||||
/usr/share/man/* \
|
||||
/usr/share/local/*
|
|
@ -1,4 +1,12 @@
|
|||
[
|
||||
{
|
||||
"name": "v1.13.1",
|
||||
"checksums": {
|
||||
"darwin": "cc7eaadea2becc48eee78136f8d569df55a28c46d58d1c8bb434895382aced78",
|
||||
"linux": "3564b685f8d797df78ebfa2f5b34c99b3c77b0d1f49eab6aab37500f1ba61d98",
|
||||
"windows": "0d315ec21ca8a34eff5fa4cc478c09ed2d48ae88b3c5d586df9de111ac414d44"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "v1.13.0",
|
||||
"checksums": {
|
||||
|
|
2
go.mod
2
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
|
||||
|
|
3
go.sum
3
go.sum
|
@ -517,6 +517,8 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <kubernetes_version>")
|
||||
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()
|
||||
}
|
||||
|
||||
info, err := os.Stat(constantsFile)
|
||||
// fetchKubernetesReleases returns respective current stable (as vDefault) and
|
||||
// latest rc or beta (as vNewest) Kubernetes GitHub Releases, and any error
|
||||
func fetchKubernetesReleases() (vDefault, vNewest string, err error) {
|
||||
client := github.NewClient(nil)
|
||||
|
||||
// set a context with a deadline - timeout after at most 10 seconds
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// walk through the paginated list of all 'kubernetes/kubernetes' repo releases
|
||||
// from latest to older releases, until latest release and pre-release are found
|
||||
// use max value (100) for PerPage to avoid hitting the rate limits (60 per hour, 10 per minute)
|
||||
// see https://godoc.org/github.com/google/go-github/github#hdr-Rate_Limiting
|
||||
opt := &github.ListOptions{PerPage: 100}
|
||||
for {
|
||||
rels, resp, err := client.Repositories.ListReleases(ctx, "kubernetes", "kubernetes", opt)
|
||||
if err != nil {
|
||||
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)
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
testData := "../../pkg/minikube/bootstrapper/bsutil/testdata"
|
||||
for _, r := range rels {
|
||||
// GetName returns the Name field if it's non-nil, zero value otherwise.
|
||||
ver := r.GetName()
|
||||
if ver == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
err = filepath.Walk(testData, func(path string, info os.FileInfo, err error) error {
|
||||
rel := strings.Split(ver, "-")
|
||||
// check if it is a release channel (ie, 'v1.19.2') or a
|
||||
// pre-release channel (ie, 'v1.19.3-rc.0' or 'v1.19.0-beta.2')
|
||||
if len(rel) == 1 && vDefault == "" {
|
||||
vDefault = ver
|
||||
} else if len(rel) > 1 && vNewest == "" {
|
||||
if strings.HasPrefix(rel[1], "rc") || strings.HasPrefix(rel[1], "beta") {
|
||||
vNewest = ver
|
||||
}
|
||||
}
|
||||
|
||||
if vDefault != "" && vNewest != "" {
|
||||
// make sure that vNewest >= vDefault
|
||||
if vNewest < vDefault {
|
||||
vNewest = vDefault
|
||||
}
|
||||
return vDefault, vNewest, nil
|
||||
}
|
||||
}
|
||||
|
||||
if resp.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
opt.Page = resp.NextPage
|
||||
}
|
||||
return vDefault, vNewest, nil
|
||||
}
|
||||
|
||||
// updateKubernetesVersions updates DefaultKubernetesVersion to vDefault release and
|
||||
// NewestKubernetesVersion to vNewest release, and returns any error
|
||||
func updateKubernetesVersions(vDefault, vNewest string) error {
|
||||
if err := replaceAllString("../../pkg/minikube/constants/constants.go", map[string]string{
|
||||
`DefaultKubernetesVersion = \".*`: "DefaultKubernetesVersion = \"" + vDefault + "\"",
|
||||
`NewestKubernetesVersion = \".*`: "NewestKubernetesVersion = \"" + vNewest + "\"",
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := replaceAllString("../../site/content/en/docs/commands/start.md", map[string]string{
|
||||
`'stable' for .*,`: "'stable' for " + vDefault + ",",
|
||||
`'latest' for .*\)`: "'latest' for " + vNewest + ")",
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update testData just for the latest 'v<MAJOR>.<MINOR>.0' from vDefault
|
||||
vDefaultMM := vDefault[:strings.LastIndex(vDefault, ".")]
|
||||
testData := "../../pkg/minikube/bootstrapper/bsutil/testdata/" + vDefaultMM
|
||||
|
||||
return filepath.Walk(testData, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.HasSuffix(path, "default.yaml") {
|
||||
return nil
|
||||
}
|
||||
cf, err = ioutil.ReadFile(path)
|
||||
return replaceAllString(path, map[string]string{
|
||||
`kubernetesVersion: .*`: "kubernetesVersion: " + vDefaultMM + ".0",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// replaceAllString replaces all occuranes of map's keys with their respective values in the file
|
||||
func replaceAllString(path string, pairs map[string]string) error {
|
||||
fb, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
re = regexp.MustCompile(`kubernetesVersion: .*`)
|
||||
cf = []byte(re.ReplaceAllString(string(cf), "kubernetesVersion: "+v))
|
||||
return ioutil.WriteFile(path, cf, info.Mode())
|
||||
})
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
glog.Errorf("Walk failed: %v", err)
|
||||
return err
|
||||
}
|
||||
mode := info.Mode()
|
||||
|
||||
f := string(fb)
|
||||
for org, new := range pairs {
|
||||
re := regexp.MustCompile(org)
|
||||
f = re.ReplaceAllString(f, new)
|
||||
}
|
||||
if err := ioutil.WriteFile(path, []byte(f), mode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import (
|
|||
|
||||
func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string) error {
|
||||
driver := kic.NewDriver(kic.Config{
|
||||
ClusterName: profile,
|
||||
KubernetesVersion: kubernetesVersion,
|
||||
ContainerRuntime: containerRuntime,
|
||||
OCIBinary: oci.Docker,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="702px" height="683px" viewBox="0 0 702 683" version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="https://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 39.1 (31720) - https://www.sketchapp.com/ -->
|
||||
<svg width="702px" height="683px" viewBox="0 0 702 683" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 39.1 (31720) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>minikube</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
|
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
@ -324,7 +324,18 @@ func verifyAddonStatus(cc *config.ClusterConfig, name string, val string) error
|
|||
}
|
||||
|
||||
func verifyGCPAuthAddon(cc *config.ClusterConfig, name string, val string) error {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -32,10 +33,13 @@ type SysInfo struct {
|
|||
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
|
||||
}
|
||||
|
|
|
@ -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 <v1.14, will try to get the IP using container gatway", containerName)
|
||||
|
||||
return containerGatewayIP(Docker, containerName)
|
||||
}
|
||||
return gateway, errors.Wrap(err, "network inspect")
|
||||
}
|
||||
return gateway, nil
|
||||
}
|
||||
// for windows and mac, the gateway ip is not routable so we use dns trick.
|
||||
return digDNS(ociBin, containerName, "host.docker.internal")
|
||||
}
|
||||
|
||||
// podman
|
||||
if runtime.GOOS == "linux" {
|
||||
return containerGatewayIP(ociBin, containerName)
|
||||
return containerGatewayIP(Podman, containerName)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("RoutableHostIPFromInside is currently only implemented for linux")
|
||||
|
@ -59,56 +68,8 @@ func digDNS(ociBin, containerName, dns string) (net.IP, error) {
|
|||
return ip, nil
|
||||
}
|
||||
|
||||
// profileInContainers checks whether the profile is within the containers list
|
||||
func profileInContainers(profile string, containers []string) bool {
|
||||
for _, container := range containers {
|
||||
if container == profile {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// dockerGatewayIP gets the default gateway ip for the docker bridge on the user's host machine
|
||||
// gets the ip from user's host docker
|
||||
func dockerGatewayIP(profile string) (net.IP, error) {
|
||||
var bridgeID string
|
||||
rr, err := runCmd(exec.Command(Docker, "network", "ls", "--filter", "name=bridge", "--format", "{{.ID}}"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get network bridge")
|
||||
}
|
||||
networksOutput := strings.TrimSpace(rr.Stdout.String())
|
||||
networksSlice := strings.Fields(networksOutput)
|
||||
// Look for the minikube container within each docker network
|
||||
for _, net := range networksSlice {
|
||||
// get all containers in the network
|
||||
rs, err := runCmd(exec.Command(Docker, "network", "inspect", net, "-f", "{{range $k, $v := .Containers}}{{$v.Name}} {{end}}"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get containers in network")
|
||||
}
|
||||
containersSlice := strings.Fields(rs.Stdout.String())
|
||||
if profileInContainers(profile, containersSlice) {
|
||||
bridgeID = net
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if bridgeID == "" {
|
||||
return nil, errors.Errorf("unable to determine bridge network id from %q", networksOutput)
|
||||
}
|
||||
rr, err = runCmd(exec.Command(Docker, "network", "inspect",
|
||||
"--format", "{{(index .IPAM.Config 0).Gateway}}", bridgeID))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "inspect IP bridge network %q.", bridgeID)
|
||||
}
|
||||
|
||||
ip := net.ParseIP(strings.TrimSpace(rr.Stdout.String()))
|
||||
glog.Infof("got host ip for mount in container by inspect docker network: %s", ip.String())
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// containerGatewayIP gets the default gateway ip for the container
|
||||
func containerGatewayIP(ociBin, containerName string) (net.IP, error) {
|
||||
func containerGatewayIP(ociBin string, containerName string) (net.IP, error) {
|
||||
rr, err := runCmd(exec.Command(ociBin, "container", "inspect", "--format", "{{.NetworkSettings.Gateway}}", containerName))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "inspect gateway")
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// firstSubnetAddr subnet to be used on first kic cluster
|
||||
// it is one octet more than the one used by KVM to avoid possible conflict
|
||||
const firstSubnetAddr = "192.168.49.0"
|
||||
|
||||
// big enough for a cluster of 254 nodes
|
||||
const defaultSubnetMask = 24
|
||||
|
||||
// CreateNetwork creates a network returns gateway and error, minikube creates one network per cluster
|
||||
func CreateNetwork(ociBin string, name string) (net.IP, error) {
|
||||
if ociBin != Docker {
|
||||
return nil, fmt.Errorf("%s network not implemented yet", ociBin)
|
||||
}
|
||||
return createDockerNetwork(name)
|
||||
}
|
||||
|
||||
func createDockerNetwork(clusterName string) (net.IP, error) {
|
||||
// check if the network already exists
|
||||
subnet, gateway, err := dockerNetworkInspect(clusterName)
|
||||
if err == nil {
|
||||
glog.Infof("Found existing network with subnet %s and gateway %s.", subnet, gateway)
|
||||
return gateway, nil
|
||||
}
|
||||
|
||||
attempts := 0
|
||||
subnetAddr := firstSubnetAddr
|
||||
// Rather than iterate through all of the valid subnets, give up at 20 to avoid a lengthy user delay for something that is unlikely to work.
|
||||
// will be like 192.168.49.0/24 ,...,192.168.239.0/24
|
||||
for attempts < 20 {
|
||||
gateway, err = tryCreateDockerNetwork(subnetAddr, defaultSubnetMask, clusterName)
|
||||
if err == nil {
|
||||
return gateway, nil
|
||||
}
|
||||
|
||||
// don't retry if error is not adddress is taken
|
||||
if !(errors.Is(err, ErrNetworkSubnetTaken) || errors.Is(err, ErrNetworkGatewayTaken)) {
|
||||
glog.Errorf("error while trying to create network %v", err)
|
||||
return nil, errors.Wrap(err, "un-retryable")
|
||||
}
|
||||
attempts++
|
||||
// Find an open subnet by incrementing the 3rd octet by 10 for each try
|
||||
// 13 times adding 10 firstSubnetAddr "192.168.49.0/24"
|
||||
// at most it will add up to 169 which is still less than max allowed 255
|
||||
// this is large enough to try more and not too small to not try enough
|
||||
// can be tuned in the next iterations
|
||||
newSubnet := net.ParseIP(subnetAddr).To4()
|
||||
newSubnet[2] += byte(9 + attempts)
|
||||
subnetAddr = newSubnet.String()
|
||||
}
|
||||
return gateway, fmt.Errorf("failed to create network after 20 attempts")
|
||||
}
|
||||
|
||||
func tryCreateDockerNetwork(subnetAddr string, subnetMask int, name string) (net.IP, error) {
|
||||
gateway := net.ParseIP(subnetAddr)
|
||||
gateway.To4()[3]++ // first ip for gateway
|
||||
glog.Infof("attempt to create network %s/%d with subnet: %s and gateway %s...", subnetAddr, subnetMask, name, gateway)
|
||||
// options documentation https://docs.docker.com/engine/reference/commandline/network_create/#bridge-driver-options
|
||||
rr, err := runCmd(exec.Command(Docker, "network", "create", "--driver=bridge", fmt.Sprintf("--subnet=%s", fmt.Sprintf("%s/%d", subnetAddr, subnetMask)), fmt.Sprintf("--gateway=%s", gateway), "-o", "--ip-masq", "-o", "--icc", fmt.Sprintf("--label=%s=%s", CreatedByLabelKey, "true"), name))
|
||||
if err != nil {
|
||||
// Pool overlaps with other one on this address space
|
||||
if strings.Contains(rr.Output(), "Pool overlaps") {
|
||||
return nil, ErrNetworkSubnetTaken
|
||||
}
|
||||
if strings.Contains(rr.Output(), "failed to allocate gateway") && strings.Contains(rr.Output(), "Address already in use") {
|
||||
return nil, ErrNetworkGatewayTaken
|
||||
}
|
||||
return nil, errors.Wrapf(err, "create network %s", fmt.Sprintf("%s %s/%d", name, subnetAddr, subnetMask))
|
||||
}
|
||||
return gateway, nil
|
||||
}
|
||||
|
||||
// returns subnet and gate if exists
|
||||
func dockerNetworkInspect(name string) (*net.IPNet, net.IP, error) {
|
||||
rr, err := runCmd(exec.Command(Docker, "network", "inspect", name, "--format", "{{(index .IPAM.Config 0).Subnet}},{{(index .IPAM.Config 0).Gateway}}"))
|
||||
if err != nil {
|
||||
if strings.Contains(rr.Output(), "No such network") {
|
||||
return nil, nil, ErrNetworkNotFound
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
// results looks like 172.17.0.0/16,172.17.0.1
|
||||
ips := strings.Split(strings.TrimSpace(rr.Stdout.String()), ",")
|
||||
if len(ips) == 0 {
|
||||
return nil, nil, fmt.Errorf("empty IP list parsed from: %q", rr.Output())
|
||||
}
|
||||
|
||||
_, subnet, err := net.ParseCIDR(ips[0])
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "parse subnet for %s", name)
|
||||
}
|
||||
var gateway net.IP
|
||||
if len(ips) > 0 {
|
||||
gateway = net.ParseIP(ips[1])
|
||||
}
|
||||
return subnet, gateway, nil
|
||||
}
|
||||
|
||||
// RemoveNetwork removes a network
|
||||
func RemoveNetwork(name string) error {
|
||||
if !networkExists(name) {
|
||||
return nil
|
||||
}
|
||||
rr, err := runCmd(exec.Command(Docker, "network", "remove", name))
|
||||
if err != nil {
|
||||
if strings.Contains(rr.Output(), "No such network") {
|
||||
return ErrNetworkNotFound
|
||||
}
|
||||
// Error response from daemon: error while removing network: network mynet123 id f9e1c50b89feb0b8f4b687f3501a81b618252c9907bc20666e386d0928322387 has active endpoints
|
||||
if strings.Contains(rr.Output(), "has active endpoints") {
|
||||
return ErrNetworkInUse
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func networkExists(name string) bool {
|
||||
_, _, err := dockerNetworkInspect(name)
|
||||
if err != nil && !errors.Is(err, ErrNetworkNotFound) { // log unexpected error
|
||||
glog.Warningf("Error inspecting docker network %s: %v", name, err)
|
||||
}
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// networkNamesByLabel returns all network names created by a label
|
||||
func networkNamesByLabel(ociBin string, label string) ([]string, error) {
|
||||
if ociBin != Docker {
|
||||
return nil, fmt.Errorf("%s not supported", ociBin)
|
||||
}
|
||||
|
||||
// docker network ls --filter='label=created_by.minikube.sigs.k8s.io=true' --format '{{.Name}}'
|
||||
rr, err := runCmd(exec.Command(Docker, "network", "ls", fmt.Sprintf("--filter=label=%s", label), "--format", "{{.Name}}"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var lines []string
|
||||
scanner := bufio.NewScanner(bytes.NewReader(rr.Stdout.Bytes()))
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, strings.TrimSpace(scanner.Text()))
|
||||
}
|
||||
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
// DeleteKICNetworks deletes all networks created by kic
|
||||
func DeleteKICNetworks() []error {
|
||||
var errs []error
|
||||
ns, err := networkNamesByLabel(Docker, CreatedByLabelKey+"=true")
|
||||
if err != nil {
|
||||
return []error{errors.Wrap(err, "list all volume")}
|
||||
}
|
||||
for _, n := range ns {
|
||||
err := RemoveNetwork(n)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -169,6 +169,11 @@ func CreateContainerNode(p CreateParams) error {
|
|||
virtualization = "podman" // VIRTUALIZATION_PODMAN
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -32,7 +32,7 @@ import (
|
|||
const domainTmpl = `
|
||||
<domain type='kvm'>
|
||||
<name>{{.MachineName}}</name>
|
||||
<memory unit='MB'>{{.Memory}}</memory>
|
||||
<memory unit='MiB'>{{.Memory}}</memory>
|
||||
<vcpu>{{.CPU}}</vcpu>
|
||||
<features>
|
||||
<acpi/>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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})
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -192,6 +192,13 @@ var (
|
|||
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}
|
||||
|
|
|
@ -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 {
|
||||
glog.Infof("docker version: %s", output)
|
||||
return checkNeedsImprovement()
|
||||
}
|
||||
|
||||
glog.Warningf("docker returned error: %v", err)
|
||||
|
||||
// Basic timeout
|
||||
if err != nil {
|
||||
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}
|
||||
err = errors.Wrapf(err, "deadline exceeded running %q", strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
||||
glog.Warningf("docker version 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)
|
||||
}
|
||||
|
||||
return registry.State{Error: err, Installed: true, Healthy: false, Doc: docURL}
|
||||
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Restart the Docker service", Doc: docURL}
|
||||
}
|
||||
|
||||
glog.Infof("docker version: %s", o)
|
||||
if strings.Contains(string(o), "windows-") {
|
||||
return registry.State{Error: oci.ErrWindowsContainers, Installed: true, Healthy: false, Fix: "Change container type to \"linux\" in Docker Desktop settings", Doc: docURL + "#verify-docker-container-type-is-linux"}
|
||||
}
|
||||
|
||||
si, err := oci.CachedDaemonInfo("docker")
|
||||
if err != nil {
|
||||
// No known fix because we haven't yet seen a failure here
|
||||
return registry.State{Error: errors.Wrap(err, "docker info"), Installed: true, Healthy: false, Doc: docURL}
|
||||
}
|
||||
|
||||
for _, serr := range si.Errors {
|
||||
return suggestFix(serr, fmt.Errorf("docker info error: %s", serr))
|
||||
}
|
||||
|
||||
return checkNeedsImprovement()
|
||||
}
|
||||
|
||||
// checkNeedsImprovement if overlay mod is installed on a system
|
||||
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package monitor
|
||||
|
||||
const (
|
||||
GithubAccessTokenEnvVar = "GITHUB_ACCESS_TOKEN"
|
||||
OkToTestLabel = "ok-to-test"
|
||||
GithubOwner = "kubernetes"
|
||||
GithubRepo = "minikube"
|
||||
BotName = "minikube-pr-bot"
|
||||
)
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// RunMkcmp runs minikube built at the given pr against minikube at master
|
||||
func RunMkcmp(ctx context.Context, pr int) (string, error) {
|
||||
// run 'git pull' so that minikube dir is up to date
|
||||
if _, err := runCmdInMinikube(ctx, []string{"git", "pull", "origin", "master"}); err != nil {
|
||||
return "", errors.Wrap(err, "running git pull")
|
||||
}
|
||||
mkcmpPath := "out/mkcmp"
|
||||
minikubePath := "out/minikube"
|
||||
if _, err := runCmdInMinikube(ctx, []string{"make", mkcmpPath, minikubePath}); err != nil {
|
||||
return "", errors.Wrap(err, "building minikube and mkcmp at head")
|
||||
}
|
||||
return runCmdInMinikube(ctx, []string{mkcmpPath, minikubePath, fmt.Sprintf("pr://%d", pr)})
|
||||
}
|
||||
|
||||
// runCmdInMinikube runs the cmd and return stdout
|
||||
func runCmdInMinikube(ctx context.Context, command []string) (string, error) {
|
||||
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||||
cmd.Dir = minikubeDir()
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd.Stdout = buf
|
||||
|
||||
log.Printf("Running: %v", cmd.Args)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", errors.Wrapf(err, "running %v: %v", cmd.Args, buf.String())
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func minikubeDir() string {
|
||||
return filepath.Join(os.Getenv("HOME"), "minikube")
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// Client provides the context and client with necessary auth
|
||||
// for interacting with the Github API
|
||||
type Client struct {
|
||||
ctx context.Context
|
||||
*github.Client
|
||||
owner string
|
||||
repo string
|
||||
}
|
||||
|
||||
// NewClient returns a github client with the necessary auth
|
||||
func NewClient(ctx context.Context, owner, repo string) *Client {
|
||||
githubToken := os.Getenv(GithubAccessTokenEnvVar)
|
||||
// Setup the token for github authentication
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: githubToken},
|
||||
)
|
||||
tc := oauth2.NewClient(context.Background(), ts)
|
||||
|
||||
// Return a client instance from github
|
||||
client := github.NewClient(tc)
|
||||
return &Client{
|
||||
ctx: ctx,
|
||||
Client: client,
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
// CommentOnPR comments message on the PR
|
||||
func (g *Client) CommentOnPR(pr int, message string) error {
|
||||
comment := &github.IssueComment{
|
||||
Body: &message,
|
||||
}
|
||||
|
||||
log.Printf("Creating comment on PR %d: %s", pr, message)
|
||||
_, _, err := g.Client.Issues.CreateComment(g.ctx, g.owner, g.repo, pr, comment)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "creating github comment")
|
||||
}
|
||||
log.Printf("Successfully commented on PR %d.", pr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListOpenPRsWithLabel returns all open PRs with the specified label
|
||||
func (g *Client) ListOpenPRsWithLabel(label string) ([]int, error) {
|
||||
validPrs := []int{}
|
||||
prs, _, err := g.Client.PullRequests.List(g.ctx, g.owner, g.repo, &github.PullRequestListOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "listing pull requests")
|
||||
}
|
||||
for _, pr := range prs {
|
||||
if prContainsLabel(pr.Labels, label) {
|
||||
validPrs = append(validPrs, pr.GetNumber())
|
||||
}
|
||||
}
|
||||
return validPrs, nil
|
||||
}
|
||||
|
||||
func prContainsLabel(labels []*github.Label, label string) bool {
|
||||
for _, l := range labels {
|
||||
if l == nil {
|
||||
continue
|
||||
}
|
||||
if l.GetName() == label {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NewCommitsExist checks if new commits exist since minikube-pr-bot
|
||||
// commented on the PR. If so, return true.
|
||||
func (g *Client) NewCommitsExist(pr int, login string) (bool, error) {
|
||||
lastCommentTime, err := g.timeOfLastComment(pr, login)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "getting time of last comment by %s on pr %d", login, pr)
|
||||
}
|
||||
lastCommitTime, err := g.timeOfLastCommit(pr)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "getting time of last commit on pr %d", pr)
|
||||
}
|
||||
return lastCommentTime.Before(lastCommitTime), nil
|
||||
}
|
||||
|
||||
func (g *Client) timeOfLastCommit(pr int) (time.Time, error) {
|
||||
var commits []*github.RepositoryCommit
|
||||
|
||||
page := 0
|
||||
resultsPerPage := 30
|
||||
for {
|
||||
c, _, err := g.Client.PullRequests.ListCommits(g.ctx, g.owner, g.repo, pr, &github.ListOptions{
|
||||
Page: page,
|
||||
PerPage: resultsPerPage,
|
||||
})
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
commits = append(commits, c...)
|
||||
if len(c) < resultsPerPage {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
lastCommitTime := time.Time{}
|
||||
for _, c := range commits {
|
||||
if newCommitTime := c.GetCommit().GetAuthor().GetDate(); newCommitTime.After(lastCommitTime) {
|
||||
lastCommitTime = newCommitTime
|
||||
}
|
||||
}
|
||||
return lastCommitTime, nil
|
||||
}
|
||||
|
||||
func (g *Client) timeOfLastComment(pr int, login string) (time.Time, error) {
|
||||
var comments []*github.IssueComment
|
||||
|
||||
page := 0
|
||||
resultsPerPage := 30
|
||||
for {
|
||||
c, _, err := g.Client.Issues.ListComments(g.ctx, g.owner, g.repo, pr, &github.IssueListCommentsOptions{
|
||||
ListOptions: github.ListOptions{
|
||||
Page: page,
|
||||
PerPage: resultsPerPage,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
comments = append(comments, c...)
|
||||
if len(c) < resultsPerPage {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
// go through comments backwards to find the most recent
|
||||
lastCommentTime := time.Time{}
|
||||
|
||||
for _, c := range comments {
|
||||
if u := c.GetUser(); u != nil {
|
||||
if u.GetLogin() == login {
|
||||
if c.GetCreatedAt().After(lastCommentTime) {
|
||||
lastCommentTime = c.GetCreatedAt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lastCommentTime, nil
|
||||
}
|
|
@ -24,7 +24,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"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 {
|
||||
|
|
|
@ -11,7 +11,6 @@ Generate command completion for a shell
|
|||
|
||||
### Synopsis
|
||||
|
||||
|
||||
Outputs minikube shell completion for the given shell (bash, zsh or fish)
|
||||
|
||||
This depends on the bash-completion binary. Example installation instructions:
|
||||
|
|
|
@ -26,7 +26,7 @@ minikube start [flags]
|
|||
--apiserver-names stringArray A set of apiserver names which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine
|
||||
--apiserver-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
|
||||
|
|
|
@ -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:
|
||||
```
|
||||
|
|
|
@ -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)).
|
||||
|
|
|
@ -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": "",
|
||||
|
@ -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": "",
|
||||
|
@ -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": "",
|
||||
|
@ -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": "",
|
||||
|
@ -299,7 +299,7 @@
|
|||
"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...": "",
|
||||
|
@ -307,7 +307,7 @@
|
|||
"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}}": "",
|
||||
|
@ -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]": "",
|
||||
|
@ -622,7 +622,7 @@
|
|||
"Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.": "",
|
||||
"Your 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\"": "",
|
||||
|
@ -667,7 +667,7 @@
|
|||
"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}}": "",
|
||||
|
|
Loading…
Reference in New Issue