diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 40dc55a120..a3572ed151 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,8 +1,10 @@ name: CI on: [pull_request] +env: + GOPROXY: https://proxy.golang.org jobs: # Runs before all other jobs - # builds the minikube binaries + # builds the minikube binaries build_minikube: env: TIME_ELAPSED: time @@ -11,7 +13,9 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - name: build binaries + - name: Download Dependencies + run : go mod download + - name: Build Binaries run : | make minikube-linux-amd64 make e2e-linux-amd64 @@ -36,11 +40,13 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - name: install libvirt - run : | + - name: Install libvirt + run : | sudo apt-get update sudo apt-get install -y libvirt-dev - - name: lint + - name: Download Dependencies + run : go mod download + - name: Lint env: TESTSUITE: lintall run : make test @@ -53,11 +59,13 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - - name: install libvirt - run : | + - name: Install libvirt + run : | sudo apt-get update sudo apt-get install -y libvirt-dev - - name: unit test + - name: Download Dependencies + run : go mod download + - name: Unit Test env: TESTSUITE: unittest run : @@ -74,16 +82,22 @@ jobs: SHELL: "/bin/bash" # To prevent https://github.com/kubernetes/minikube/issues/6643 runs-on: ubuntu-16.04 steps: + - name: Docker Info + shell: bash + run: | + docker info || true + docker version || true + docker ps || true - name: Install gopogh shell: bash run: | curl -LO https://github.com/medyagh/gopogh/releases/download/v0.1.16/gopogh-linux-amd64 sudo install gopogh-linux-amd64 /usr/local/bin/gopogh - - name: Download binaries + - name: Download Binaries uses: actions/download-artifact@v1 with: name: minikube_binaries - - name: Run integration test + - name: Run Integration Test continue-on-error: true # bash {0} to allow test to continue to next step. in case of shell: bash {0} @@ -96,12 +110,12 @@ jobs: START_TIME=$(date -u +%s) KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome ./e2e-linux-amd64 -minikube-start-args=--vm-driver=docker -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt END_TIME=$(date -u +%s) - TIME_ELAPSED=$(($END_TIME-$START_TIME)) + TIME_ELAPSED=$(($END_TIME-$START_TIME)) min=$((${TIME_ELAPSED}/60)) sec=$((${TIME_ELAPSED}%60)) TIME_ELAPSED="${min} min $sec seconds " echo ::set-env name=TIME_ELAPSED::${TIME_ELAPSED} - - name: Generate html report + - name: Generate HTML Report shell: bash run: | cd minikube_binaries @@ -110,7 +124,7 @@ jobs: STAT=$(gopogh -in ./report/testout.json -out ./report/testout.html -name "${JOB_NAME} ${GITHUB_REF}" -repo "${GITHUB_REPOSITORY}" -details "${GITHUB_SHA}") || true echo status: ${STAT} FailNum=$(echo $STAT | jq '.NumberOfFail') - TestsNum=$(echo $STAT | jq '.NumberOfTests') + TestsNum=$(echo $STAT | jq '.NumberOfTests') GOPOGH_RESULT="${JOB_NAME} : completed with ${FailNum} / ${TestsNum} failures in ${TIME_ELAPSED}" echo ::set-env name=GOPOGH_RESULT::${GOPOGH_RESULT} echo ::set-env name=STAT::${STAT} @@ -136,16 +150,22 @@ jobs: SHELL: "/bin/bash" # To prevent https://github.com/kubernetes/minikube/issues/6643 needs: [build_minikube] steps: + - name: Docker Info + shell: bash + run: | + docker info || true + docker version || true + docker ps || true - name: Install gopogh shell: bash run: | curl -LO https://github.com/medyagh/gopogh/releases/download/v0.1.16/gopogh-linux-amd64 sudo install gopogh-linux-amd64 /usr/local/bin/gopogh - - name: Download binaries + - name: Download Binaries uses: actions/download-artifact@v1 with: name: minikube_binaries - - name: Run integration test + - name: Run Integration Test continue-on-error: true # bash {0} to allow test to continue to next step. in case of shell: bash {0} @@ -156,14 +176,14 @@ jobs: chmod a+x e2e-* chmod a+x minikube-* START_TIME=$(date -u +%s) - KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome ./e2e-linux-amd64 -minikube-start-args=--vm-driver=docker -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt + KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome ./e2e-linux-amd64 -minikube-start-args=--driver=docker -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt END_TIME=$(date -u +%s) - TIME_ELAPSED=$(($END_TIME-$START_TIME)) + TIME_ELAPSED=$(($END_TIME-$START_TIME)) min=$((${TIME_ELAPSED}/60)) sec=$((${TIME_ELAPSED}%60)) TIME_ELAPSED="${min} min $sec seconds " echo ::set-env name=TIME_ELAPSED::${TIME_ELAPSED} - - name: Generate html report + - name: Generate HTML Report shell: bash run: | cd minikube_binaries @@ -172,7 +192,7 @@ jobs: STAT=$(gopogh -in ./report/testout.json -out ./report/testout.html -name "${JOB_NAME} ${GITHUB_REF}" -repo "${GITHUB_REPOSITORY}" -details "${GITHUB_SHA}") || true echo status: ${STAT} FailNum=$(echo $STAT | jq '.NumberOfFail') - TestsNum=$(echo $STAT | jq '.NumberOfTests') + TestsNum=$(echo $STAT | jq '.NumberOfTests') GOPOGH_RESULT="${JOB_NAME} : completed with ${FailNum} / ${TestsNum} failures in ${TIME_ELAPSED}" echo ::set-env name=GOPOGH_RESULT::${GOPOGH_RESULT} echo ::set-env name=STAT::${STAT} @@ -203,11 +223,11 @@ jobs: run: | curl -LO https://github.com/medyagh/gopogh/releases/download/v0.1.16/gopogh-linux-amd64 sudo install gopogh-linux-amd64 /usr/local/bin/gopogh - - name: Download binaries + - name: Download Binaries uses: actions/download-artifact@v1 with: name: minikube_binaries - - name: Run integration test + - name: Run Integration Test continue-on-error: true # bash {0} to allow test to continue to next step. in case of shell: bash {0} @@ -218,14 +238,14 @@ jobs: chmod a+x e2e-* chmod a+x minikube-* START_TIME=$(date -u +%s) - KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome sudo -E ./e2e-linux-amd64 -minikube-start-args=--vm-driver=none -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt + KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome sudo -E ./e2e-linux-amd64 -minikube-start-args=--driver=none -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt END_TIME=$(date -u +%s) - TIME_ELAPSED=$(($END_TIME-$START_TIME)) + TIME_ELAPSED=$(($END_TIME-$START_TIME)) min=$((${TIME_ELAPSED}/60)) sec=$((${TIME_ELAPSED}%60)) TIME_ELAPSED="${min} min $sec seconds " echo ::set-env name=TIME_ELAPSED::${TIME_ELAPSED} - - name: Generate html report + - name: Generate HTML Report shell: bash run: | cd minikube_binaries @@ -234,7 +254,7 @@ jobs: STAT=$(gopogh -in ./report/testout.json -out ./report/testout.html -name "${JOB_NAME} ${GITHUB_REF}" -repo "${GITHUB_REPOSITORY}" -details "${GITHUB_SHA}") || true echo status: ${STAT} FailNum=$(echo $STAT | jq '.NumberOfFail') - TestsNum=$(echo $STAT | jq '.NumberOfTests') + TestsNum=$(echo $STAT | jq '.NumberOfTests') GOPOGH_RESULT="${JOB_NAME} : completed with ${FailNum} / ${TestsNum} failures in ${TIME_ELAPSED}" echo ::set-env name=GOPOGH_RESULT::${GOPOGH_RESULT} echo ::set-env name=STAT::${STAT} @@ -264,12 +284,12 @@ jobs: shell: bash run: | curl -LO https://github.com/medyagh/gopogh/releases/download/v0.1.16/gopogh-linux-amd64 - sudo install gopogh-linux-amd64 /usr/local/bin/gopogh - - name: Download binaries + sudo install gopogh-linux-amd64 /usr/local/bin/gopogh + - name: Download Binaries uses: actions/download-artifact@v1 with: name: minikube_binaries - - name: Run integration test + - name: Run Integration Test continue-on-error: true # bash {0} to allow test to continue to next step. in case of shell: bash {0} @@ -280,14 +300,14 @@ jobs: chmod a+x e2e-* chmod a+x minikube-* START_TIME=$(date -u +%s) - KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome sudo -E ./e2e-linux-amd64 -minikube-start-args=--vm-driver=none -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt + KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome sudo -E ./e2e-linux-amd64 -minikube-start-args=--driver=none -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt END_TIME=$(date -u +%s) - TIME_ELAPSED=$(($END_TIME-$START_TIME)) + TIME_ELAPSED=$(($END_TIME-$START_TIME)) min=$((${TIME_ELAPSED}/60)) sec=$((${TIME_ELAPSED}%60)) TIME_ELAPSED="${min} min $sec seconds " echo ::set-env name=TIME_ELAPSED::${TIME_ELAPSED} - - name: Generate html report + - name: Generate HTML Report shell: bash run: | cd minikube_binaries @@ -296,7 +316,7 @@ jobs: STAT=$(gopogh -in ./report/testout.json -out ./report/testout.html -name "${JOB_NAME} ${GITHUB_REF}" -repo "${GITHUB_REPOSITORY}" -details "${GITHUB_SHA}") || true echo status: ${STAT} FailNum=$(echo $STAT | jq '.NumberOfFail') - TestsNum=$(echo $STAT | jq '.NumberOfTests') + TestsNum=$(echo $STAT | jq '.NumberOfTests') GOPOGH_RESULT="${JOB_NAME} : completed with ${FailNum} / ${TestsNum} failures in ${TIME_ELAPSED}" echo ::set-env name=GOPOGH_RESULT::${GOPOGH_RESULT} echo ::set-env name=STAT::${STAT} @@ -331,8 +351,8 @@ jobs: sudo apt-key add - < Release.key || true sudo apt-get update -qq sudo apt-get -qq -y install podman - sudo podman version || true - sudo podman info || true + sudo podman version || true + sudo podman info || true - name: Install gopogh shell: bash run: | @@ -342,7 +362,7 @@ jobs: uses: actions/download-artifact@v1 with: name: minikube_binaries - - name: Run integration test + - name: Run Integration Test continue-on-error: true # bash {0} to allow test to continue to next step. in case of shell: bash {0} @@ -353,14 +373,14 @@ jobs: chmod a+x e2e-* chmod a+x minikube-* START_TIME=$(date -u +%s) - KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome sudo -E ./e2e-linux-amd64 -minikube-start-args=--vm-driver=podman -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt + KUBECONFIG=$(pwd)/testhome/kubeconfig MINIKUBE_HOME=$(pwd)/testhome sudo -E ./e2e-linux-amd64 -minikube-start-args=--driver=podman -test.timeout=70m -test.v -timeout-multiplier=3 -binary=./minikube-linux-amd64 2>&1 | tee ./report/testout.txt END_TIME=$(date -u +%s) - TIME_ELAPSED=$(($END_TIME-$START_TIME)) + TIME_ELAPSED=$(($END_TIME-$START_TIME)) min=$((${TIME_ELAPSED}/60)) sec=$((${TIME_ELAPSED}%60)) TIME_ELAPSED="${min} min $sec seconds " echo ::set-env name=TIME_ELAPSED::${TIME_ELAPSED} - - name: Generate html report + - name: Generate HTML Report shell: bash run: | cd minikube_binaries @@ -369,7 +389,7 @@ jobs: STAT=$(gopogh -in ./report/testout.json -out ./report/testout.html -name "${JOB_NAME} ${GITHUB_REF}" -repo "${GITHUB_REPOSITORY}" -details "${GITHUB_SHA}") || true echo status: ${STAT} FailNum=$(echo $STAT | jq '.NumberOfFail') - TestsNum=$(echo $STAT | jq '.NumberOfTests') + TestsNum=$(echo $STAT | jq '.NumberOfTests') GOPOGH_RESULT="${JOB_NAME} : completed with ${FailNum} / ${TestsNum} failures in ${TIME_ELAPSED}" echo ::set-env name=GOPOGH_RESULT::${GOPOGH_RESULT} echo ::set-env name=STAT::${STAT} @@ -386,14 +406,14 @@ jobs: echo $STAT | jq '.FailedTests' || true echo "-------------------------------------------------------" if [ "$numFail" -gt 0 ];then echo "*** $numFail Failed ***";exit 2;fi - # After all 4 integration tests finished + # After all 4 integration tests finished # collect all the reports and upload upload_all_reports: if: always() needs: [docker_ubuntu_16_04,docker_ubuntu_18_04,none_ubuntu16_04,none_ubuntu18_04,podman_ubuntu_18_04] runs-on: ubuntu-18.04 steps: - - name: download results docker_ubuntu_16_04 + - name: Download Results docker_ubuntu_16_04 uses: actions/download-artifact@v1 with: name: docker_ubuntu_16_04 @@ -403,7 +423,7 @@ jobs: run: | mkdir -p all_reports cp -r docker_ubuntu_16_04 ./all_reports/ - - name: download results docker_ubuntu_18_04 + - name: Download Results docker_ubuntu_18_04 uses: actions/download-artifact@v1 with: name: docker_ubuntu_18_04 @@ -413,7 +433,7 @@ jobs: run: | mkdir -p all_reports cp -r docker_ubuntu_18_04 ./all_reports/ - - name: download results none_ubuntu16_04 + - name: Download Results none_ubuntu16_04 uses: actions/download-artifact@v1 with: name: none_ubuntu16_04 @@ -423,21 +443,21 @@ jobs: run: | mkdir -p all_reports cp -r none_ubuntu16_04 ./all_reports/ - - name: download results none_ubuntu18_04 + - name: Download Results none_ubuntu18_04 uses: actions/download-artifact@v1 with: name: none_ubuntu18_04 - - name: cp none_ubuntu18_04 to all_report + - name: Copy none_ubuntu18_04 to all_report continue-on-error: true shell: bash {0} run: | mkdir -p all_reports cp -r none_ubuntu18_04 ./all_reports/ - - name: download results podman_ubuntu_18_04 + - name: Download Results podman_ubuntu_18_04 uses: actions/download-artifact@v1 with: name: podman_ubuntu_18_04 - - name: cp podman_ubuntu_18_04 to all_report + - name: Copy podman_ubuntu_18_04 to all_report continue-on-error: true shell: bash {0} run: | diff --git a/.travis.yml b/.travis.yml index 0afe314102..99a3207565 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ os: linux language: go go: - - 1.13.4 + - 1.13.6 env: global: - GOPROXY=https://proxy.golang.org @@ -11,7 +11,7 @@ matrix: include: - language: go name: Code Lint - go: 1.13.4 + go: 1.13.6 env: - TESTSUITE=lintall before_install: @@ -20,7 +20,7 @@ matrix: - language: go name: Unit Test - go: 1.13.4 + go: 1.13.6 env: - TESTSUITE=unittest before_install: @@ -29,7 +29,7 @@ matrix: - language: go name: Build - go: 1.13.4 + go: 1.13.6 script: make after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/Makefile b/Makefile index fcf125bcd3..4571aeb5a8 100755 --- a/Makefile +++ b/Makefile @@ -19,8 +19,10 @@ VERSION_BUILD ?= 3 RAW_VERSION=$(VERSION_MAJOR).$(VERSION_MINOR).${VERSION_BUILD} VERSION ?= v$(RAW_VERSION) -KUBERNETES_VERSION ?= $(shell egrep "^var DefaultKubernetesVersion" pkg/minikube/constants/constants.go | cut -d \" -f2) +KUBERNETES_VERSION ?= $(shell egrep "DefaultKubernetesVersion =" pkg/minikube/constants/constants.go | cut -d \" -f2) KIC_VERSION ?= $(shell egrep "Version =" pkg/drivers/kic/types.go | cut -d \" -f2) +PRELOADED_TARBALL_VERSION ?= $(shell egrep "PreloadVersion =" pkg/minikube/download/preload.go | cut -d \" -f2) +PRELOADED_VOLUMES_GCS_BUCKET ?= $(shell egrep "PreloadBucket =" pkg/minikube/download/preload.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).3 @@ -29,7 +31,7 @@ DEB_VERSION ?= $(subst -,~,$(RAW_VERSION)) RPM_VERSION ?= $(DEB_VERSION) # used by hack/jenkins/release_build_and_upload.sh and KVM_BUILD_IMAGE, see also BUILD_IMAGE below -GO_VERSION ?= 1.13.4 +GO_VERSION ?= 1.13.6 INSTALL_SIZE ?= $(shell du out/minikube-windows-amd64.exe | cut -f1) BUILDROOT_BRANCH ?= 2019.02.9 @@ -243,7 +245,7 @@ test-pkg/%: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go go test -v -test.timeout=60m ./$* --tags="$(MINIKUBE_BUILD_TAGS)" .PHONY: all -all: cross drivers e2e-cross out/gvisor-addon ## Build all different minikube components +all: cross drivers e2e-cross exotic out/gvisor-addon ## Build all different minikube components .PHONY: drivers drivers: docker-machine-driver-hyperkit docker-machine-driver-kvm2 ## Build Hyperkit and KVM2 drivers @@ -260,7 +262,7 @@ integration: out/minikube ## Trigger minikube integration test .PHONY: integration-none-driver integration-none-driver: e2e-linux-$(GOARCH) out/minikube-linux-$(GOARCH) ## Trigger minikube none driver test - sudo -E out/e2e-linux-$(GOARCH) -testdata-dir "test/integration/testdata" -minikube-start-args="--vm-driver=none" -test.v -test.timeout=60m -binary=out/minikube-linux-amd64 $(TEST_ARGS) + sudo -E out/e2e-linux-$(GOARCH) -testdata-dir "test/integration/testdata" -minikube-start-args="--driver=none" -test.v -test.timeout=60m -binary=out/minikube-linux-amd64 $(TEST_ARGS) .PHONY: integration-versioned integration-versioned: out/minikube ## Trigger minikube integration testing @@ -302,7 +304,10 @@ endif @sed -i -e 's/Json/JSON/' $@ && rm -f ./-e .PHONY: cross -cross: minikube-linux-amd64 minikube-linux-arm64 minikube-darwin-amd64 minikube-windows-amd64.exe ## Build minikube for all platform +cross: minikube-linux-amd64 minikube-darwin-amd64 minikube-windows-amd64.exe ## Build minikube for all platform + +.PHONY: exotic +exotic: out/minikube-linux-arm out/minikube-linux-arm64 out/minikube-linux-ppc64le out/minikube-linux-s390x ## Build minikube for non-amd64 linux .PHONY: windows windows: minikube-windows-amd64.exe ## Build minikube for Windows 64bit @@ -318,7 +323,8 @@ e2e-cross: e2e-linux-amd64 e2e-darwin-amd64 e2e-windows-amd64.exe ## End-to-end .PHONY: checksum checksum: ## Generate checksums - for f in out/minikube.iso out/minikube-linux-amd64 minikube-linux-arm64 \ + for f in out/minikube.iso out/minikube-linux-amd64 out/minikube-linux-arm \ + out/minikube-linux-arm64 out/minikube-linux-ppc64le out/minikube-linux-s390x \ out/minikube-darwin-amd64 out/minikube-windows-amd64.exe \ out/docker-machine-driver-kvm2 out/docker-machine-driver-hyperkit; do \ if [ -f "$${f}" ]; then \ @@ -364,8 +370,14 @@ out/linters/golangci-lint-$(GOLINT_VERSION): # this one is meant for local use .PHONY: lint +ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y) +lint: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go + docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:$(GOLINT_VERSION) \ + golangci-lint run ${GOLINT_OPTIONS} --skip-dirs "cmd/drivers/kvm|cmd/drivers/hyperkit|pkg/drivers/kvm|pkg/drivers/hyperkit" ./... +else lint: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go out/linters/golangci-lint-$(GOLINT_VERSION) ## Run lint ./out/linters/golangci-lint-$(GOLINT_VERSION) run ${GOLINT_OPTIONS} ./... +endif # lint-ci is slower version of lint and is meant to be used in ci (travis) to avoid out of memory leaks. .PHONY: lint-ci @@ -433,15 +445,13 @@ out/repodata/repomd.xml: out/minikube-$(RPM_VERSION).rpm .SECONDEXPANSION: TAR_TARGETS_linux-amd64 := out/minikube-linux-amd64 out/docker-machine-driver-kvm2 -TAR_TARGETS_linux-arm64 := out/minikube-linux-arm64 TAR_TARGETS_darwin-amd64 := out/minikube-darwin-amd64 out/docker-machine-driver-hyperkit TAR_TARGETS_windows-amd64 := out/minikube-windows-amd64.exe out/minikube-%.tar.gz: $$(TAR_TARGETS_$$*) tar -cvzf $@ $^ .PHONY: cross-tars -cross-tars: out/minikube-linux-amd64.tar.gz out/minikube-linux-arm64.tar.gz \ ## Cross-compile minikube - out/minikube-windows-amd64.tar.gz out/minikube-darwin-amd64.tar.gz +cross-tars: out/minikube-linux-amd64.tar.gz out/minikube-windows-amd64.tar.gz out/minikube-darwin-amd64.tar.gz ## Cross-compile minikube -cd out && $(SHA512SUM) *.tar.gz > SHA512SUM out/minikube-installer.exe: out/minikube-windows-amd64.exe @@ -515,15 +525,14 @@ kic-base-image: ## builds the base image used for kic. docker rmi -f $(REGISTRY)/kicbase:$(KIC_VERSION)-snapshot || true docker build -f ./hack/images/kicbase.Dockerfile -t $(REGISTRY)/kicbase:$(KIC_VERSION)-snapshot --build-arg COMMIT_SHA=${VERSION}-$(COMMIT) --target base . - -.PHONY: kic-preloaded-base-image -kic-preloaded-base-image: generate-preloaded-images-tar ## builds the base image used for kic. - docker rmi -f $(REGISTRY)/kicbase:$(KIC_VERSION)-k8s-${KUBERNETES_VERSION} || true - docker build -f ./hack/images/kicbase.Dockerfile -t $(REGISTRY)/kicbase:$(KIC_VERSION)-k8s-${KUBERNETES_VERSION} --build-arg COMMIT_SHA=${VERSION}-$(COMMIT) --build-arg KUBERNETES_VERSION=${KUBERNETES_VERSION} . +.PHONY: upload-preloaded-images-tar +upload-preloaded-images-tar: generate-preloaded-images-tar # Upload the preloaded images tar to the GCS bucket. Specify a specific kubernetes version to build via `KUBERNETES_VERSION=vx.y.z make upload-preloaded-images-tar`. + gsutil cp out/preloaded-images-k8s-${PRELOADED_TARBALL_VERSION}-${KUBERNETES_VERSION}-docker-overlay2.tar.lz4 gs://${PRELOADED_VOLUMES_GCS_BUCKET} + gsutil acl ch -u AllUsers:R gs://${PRELOADED_VOLUMES_GCS_BUCKET}/preloaded-images-k8s-${PRELOADED_TARBALL_VERSION}-${KUBERNETES_VERSION}-docker-overlay2.tar.lz4 .PHONY: generate-preloaded-images-tar -generate-preloaded-images-tar: out/minikube - go run ./hack/preload-images/preload_images.go -kubernetes-version ${KUBERNETES_VERSION} +generate-preloaded-images-tar: + go run ./hack/preload-images/preload_images.go -kubernetes-version ${KUBERNETES_VERSION} -preloaded-tarball-version ${PRELOADED_TARBALL_VERSION} .PHONY: push-storage-provisioner-image diff --git a/cmd/minikube/cmd/config/addons_list.go b/cmd/minikube/cmd/config/addons_list.go index 8737fe2224..73c72ec37e 100644 --- a/cmd/minikube/cmd/config/addons_list.go +++ b/cmd/minikube/cmd/config/addons_list.go @@ -98,7 +98,7 @@ var printAddonsList = func() { table.SetAutoFormatHeaders(true) table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true}) table.SetCenterSeparator("|") - pName := viper.GetString(config.MachineProfile) + pName := viper.GetString(config.ProfileName) for _, addonName := range addonNames { addonBundle := assets.Addons[addonName] @@ -123,7 +123,7 @@ var printAddonsList = func() { var printAddonsJSON = func() { addonNames := make([]string, 0, len(assets.Addons)) - pName := viper.GetString(config.MachineProfile) + pName := viper.GetString(config.ProfileName) for addonName := range assets.Addons { addonNames = append(addonNames, addonName) } diff --git a/cmd/minikube/cmd/config/config.go b/cmd/minikube/cmd/config/config.go index 3d7e8c7667..aa6a603068 100644 --- a/cmd/minikube/cmd/config/config.go +++ b/cmd/minikube/cmd/config/config.go @@ -42,6 +42,12 @@ type Setting struct { // These are all the settings that are configurable // and their validation and callback fn run on Set var settings = []Setting{ + { + name: "driver", + set: SetString, + validations: []setFn{IsValidDriver}, + callbacks: []setFn{RequiresRestartMsg}, + }, { name: "vm-driver", set: SetString, @@ -126,7 +132,7 @@ var settings = []Setting{ set: SetBool, }, { - name: config.MachineProfile, + name: config.ProfileName, set: SetString, }, { @@ -172,7 +178,7 @@ var settings = []Setting{ var ConfigCmd = &cobra.Command{ Use: "config SUBCOMMAND [flags]", Short: "Modify minikube config", - Long: `config modifies minikube config files using subcommands like "minikube config set vm-driver kvm" + Long: `config modifies minikube config files using subcommands like "minikube config set driver kvm" Configurable fields: ` + "\n\n" + configurableFields(), Run: func(cmd *cobra.Command, args []string) { if err := cmd.Help(); err != nil { diff --git a/cmd/minikube/cmd/config/disable.go b/cmd/minikube/cmd/config/disable.go index e9916a8929..af050c105e 100644 --- a/cmd/minikube/cmd/config/disable.go +++ b/cmd/minikube/cmd/config/disable.go @@ -35,7 +35,7 @@ var addonsDisableCmd = &cobra.Command{ } addon := args[0] - err := addons.Set(addon, "false", viper.GetString(config.MachineProfile)) + err := addons.Set(addon, "false", viper.GetString(config.ProfileName)) if err != nil { exit.WithError("disable failed", err) } diff --git a/cmd/minikube/cmd/config/enable.go b/cmd/minikube/cmd/config/enable.go index 8bef60235a..5f325a6eed 100644 --- a/cmd/minikube/cmd/config/enable.go +++ b/cmd/minikube/cmd/config/enable.go @@ -34,7 +34,7 @@ var addonsEnableCmd = &cobra.Command{ exit.UsageT("usage: minikube addons enable ADDON_NAME") } addon := args[0] - err := addons.Set(addon, "true", viper.GetString(config.MachineProfile)) + err := addons.Set(addon, "true", viper.GetString(config.ProfileName)) if err != nil { exit.WithError("enable failed", err) } diff --git a/cmd/minikube/cmd/config/get_test.go b/cmd/minikube/cmd/config/get_test.go index 4f034c8ffe..34d5b0ffac 100644 --- a/cmd/minikube/cmd/config/get_test.go +++ b/cmd/minikube/cmd/config/get_test.go @@ -30,7 +30,7 @@ func TestGetNotFound(t *testing.T) { func TestGetOK(t *testing.T) { createTestConfig(t) - name := "vm-driver" + name := "driver" err := Set(name, "virtualbox") if err != nil { t.Fatalf("Set returned error for property %s, %+v", name, err) diff --git a/cmd/minikube/cmd/config/open.go b/cmd/minikube/cmd/config/open.go index e3782e816f..8ccb74eedd 100644 --- a/cmd/minikube/cmd/config/open.go +++ b/cmd/minikube/cmd/config/open.go @@ -26,7 +26,9 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/assets" + "k8s.io/minikube/pkg/minikube/config" pkg_config "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" @@ -67,8 +69,16 @@ var addonsOpenCmd = &cobra.Command{ } defer api.Close() - profileName := viper.GetString(pkg_config.MachineProfile) - if !machine.IsHostRunning(api, profileName) { + profileName := viper.GetString(pkg_config.ProfileName) + cc, err := config.Load(profileName) + if err != nil { + exit.WithError("Error getting cluster", err) + } + cp, err := config.PrimaryControlPlane(*cc) + if err != nil { + exit.WithError("Error getting control plane", err) + } + if !machine.IsHostRunning(api, driver.MachineName(*cc, cp)) { os.Exit(1) } addon, ok := assets.Addons[addonName] // validate addon input diff --git a/cmd/minikube/cmd/config/profile.go b/cmd/minikube/cmd/config/profile.go index 280bb1c237..31bd0bb0af 100644 --- a/cmd/minikube/cmd/config/profile.go +++ b/cmd/minikube/cmd/config/profile.go @@ -35,7 +35,7 @@ var ProfileCmd = &cobra.Command{ Long: "profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { - profile := viper.GetString(pkgConfig.MachineProfile) + profile := viper.GetString(pkgConfig.ProfileName) out.T(out.Empty, profile) os.Exit(0) } @@ -65,10 +65,11 @@ var ProfileCmd = &cobra.Command{ } if !pkgConfig.ProfileExists(profile) { - out.FailureT("if you want to create a profile you can by this command: minikube start -p {{.profile_name}}", out.V{"profile_name": profile}) + out.ErrT(out.Tip, `if you want to create a profile you can by this command: minikube start -p {{.profile_name}}`, out.V{"profile_name": profile}) + os.Exit(0) } - err := Set(pkgConfig.MachineProfile, profile) + err := Set(pkgConfig.ProfileName, profile) if err != nil { exit.WithError("Setting profile failed", err) } diff --git a/cmd/minikube/cmd/config/profile_list.go b/cmd/minikube/cmd/config/profile_list.go index 9f0b0d8259..d8f0ae19d1 100644 --- a/cmd/minikube/cmd/config/profile_list.go +++ b/cmd/minikube/cmd/config/profile_list.go @@ -24,6 +24,7 @@ import ( "strings" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" @@ -75,14 +76,13 @@ var printProfilesTable = func() { defer api.Close() for _, p := range validProfiles { - p.Status, err = machine.GetHostStatus(api, p.Name) - if err != nil { - glog.Warningf("error getting host status for %s: %v", p.Name, err) - } cp, err := config.PrimaryControlPlane(*p.Config) if err != nil { - glog.Errorf("%q has no control plane: %v", p.Name, err) - // Print the data we know about anyways + exit.WithError("error getting primary control plane", err) + } + p.Status, err = machine.GetHostStatus(api, driver.MachineName(*p.Config, cp)) + if err != nil { + glog.Warningf("error getting host status for %s: %v", p.Name, err) } validData = append(validData, []string{p.Name, p.Config.Driver, p.Config.KubernetesConfig.ContainerRuntime, cp.IP, strconv.Itoa(cp.Port), p.Config.KubernetesConfig.KubernetesVersion, p.Status}) } @@ -103,7 +103,7 @@ var printProfilesTable = func() { } if err != nil { - exit.WithCodeT(exit.Config, fmt.Sprintf("error loading profiles: %v", err)) + glog.Warningf("error loading profiles: %v", err) } } @@ -117,7 +117,11 @@ var printProfilesJSON = func() { validProfiles, invalidProfiles, err := config.ListProfiles() for _, v := range validProfiles { - status, err := machine.GetHostStatus(api, v.Name) + cp, err := config.PrimaryControlPlane(*v.Config) + if err != nil { + exit.WithError("error getting primary control plane", err) + } + status, err := machine.GetHostStatus(api, driver.MachineName(*v.Config, cp)) if err != nil { glog.Warningf("error getting host status for %s: %v", v.Name, err) } diff --git a/cmd/minikube/cmd/config/set_test.go b/cmd/minikube/cmd/config/set_test.go index 8b7db4bb07..db7ee262db 100644 --- a/cmd/minikube/cmd/config/set_test.go +++ b/cmd/minikube/cmd/config/set_test.go @@ -34,25 +34,25 @@ func TestNotFound(t *testing.T) { func TestSetNotAllowed(t *testing.T) { createTestConfig(t) - err := Set("vm-driver", "123456") - if err == nil || err.Error() != "run validations for \"vm-driver\" with value of \"123456\": [driver \"123456\" is not supported]" { + err := Set("driver", "123456") + if err == nil || err.Error() != "run validations for \"driver\" with value of \"123456\": [driver \"123456\" is not supported]" { t.Fatalf("Set did not return error for unallowed value: %+v", err) } } func TestSetOK(t *testing.T) { createTestConfig(t) - err := Set("vm-driver", "virtualbox") + err := Set("driver", "virtualbox") defer func() { - err = Unset("vm-driver") + err = Unset("driver") if err != nil { - t.Errorf("failed to unset vm-driver: %+v", err) + t.Errorf("failed to unset driver: %+v", err) } }() if err != nil { t.Fatalf("Set returned error for valid property value: %+v", err) } - val, err := Get("vm-driver") + val, err := Get("driver") if err != nil { t.Fatalf("Get returned error for valid property: %+v", err) } diff --git a/cmd/minikube/cmd/config/util_test.go b/cmd/minikube/cmd/config/util_test.go index 1310b95cbf..b085ea965f 100644 --- a/cmd/minikube/cmd/config/util_test.go +++ b/cmd/minikube/cmd/config/util_test.go @@ -25,7 +25,7 @@ import ( ) var minikubeConfig = pkgConfig.MinikubeConfig{ - "vm-driver": driver.KVM2, + "driver": driver.KVM2, "cpus": 12, "show-libmachine-logs": true, } @@ -38,17 +38,17 @@ func TestFindSettingNotFound(t *testing.T) { } func TestFindSetting(t *testing.T) { - s, err := findSetting("vm-driver") + s, err := findSetting("driver") if err != nil { - t.Fatalf("Couldn't find setting, vm-driver: %v", err) + t.Fatalf("Couldn't find setting, driver: %v", err) } - if s.name != "vm-driver" { - t.Fatalf("Found wrong setting, expected vm-driver, got %s", s.name) + if s.name != "driver" { + t.Fatalf("Found wrong setting, expected driver, got %s", s.name) } } func TestSetString(t *testing.T) { - err := SetString(minikubeConfig, "vm-driver", driver.VirtualBox) + err := SetString(minikubeConfig, "driver", driver.VirtualBox) if err != nil { t.Fatalf("Couldn't set string: %v", err) } diff --git a/cmd/minikube/cmd/config/validations_test.go b/cmd/minikube/cmd/config/validations_test.go index 7662859298..0cfc87f5c7 100644 --- a/cmd/minikube/cmd/config/validations_test.go +++ b/cmd/minikube/cmd/config/validations_test.go @@ -51,7 +51,7 @@ func TestDriver(t *testing.T) { }, } - runValidations(t, tests, "vm-driver", IsValidDriver) + runValidations(t, tests, "driver", IsValidDriver) } diff --git a/cmd/minikube/cmd/dashboard.go b/cmd/minikube/cmd/dashboard.go index 802b57d922..e674e24fb5 100644 --- a/cmd/minikube/cmd/dashboard.go +++ b/cmd/minikube/cmd/dashboard.go @@ -35,7 +35,9 @@ import ( "github.com/spf13/viper" pkgaddons "k8s.io/minikube/pkg/addons" "k8s.io/minikube/pkg/minikube/assets" + "k8s.io/minikube/pkg/minikube/config" pkg_config "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" @@ -57,7 +59,7 @@ var dashboardCmd = &cobra.Command{ Short: "Access the kubernetes dashboard running within the minikube cluster", Long: `Access the kubernetes dashboard running within the minikube cluster`, Run: func(cmd *cobra.Command, args []string) { - profileName := viper.GetString(pkg_config.MachineProfile) + profileName := viper.GetString(pkg_config.ProfileName) cc, err := pkg_config.Load(profileName) if err != nil && !pkg_config.IsNotExist(err) { exit.WithError("Error loading profile config", err) @@ -80,7 +82,13 @@ var dashboardCmd = &cobra.Command{ exit.WithError("Error getting client", err) } - if _, err = api.Load(cc.Name); err != nil { + cp, err := config.PrimaryControlPlane(*cc) + if err != nil { + exit.WithError("Error getting primary control plane", err) + } + + machineName := driver.MachineName(*cc, cp) + if _, err = api.Load(machineName); err != nil { switch err := errors.Cause(err).(type) { case mcnerror.ErrHostDoesNotExist: exit.WithCodeT(exit.Unavailable, "{{.name}} cluster does not exist", out.V{"name": cc.Name}) @@ -101,7 +109,7 @@ var dashboardCmd = &cobra.Command{ exit.WithCodeT(exit.NoInput, "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/") } - if !machine.IsHostRunning(api, profileName) { + if !machine.IsHostRunning(api, machineName) { os.Exit(1) } @@ -127,7 +135,7 @@ var dashboardCmd = &cobra.Command{ } out.ErrT(out.Launch, "Launching proxy ...") - p, hostPort, err := kubectlProxy(kubectl, cc.Name) + p, hostPort, err := kubectlProxy(kubectl, machineName) if err != nil { exit.WithError("kubectl proxy", err) } diff --git a/cmd/minikube/cmd/delete.go b/cmd/minikube/cmd/delete.go index 892a851c67..3fb2aab05c 100644 --- a/cmd/minikube/cmd/delete.go +++ b/cmd/minikube/cmd/delete.go @@ -35,7 +35,6 @@ import ( "k8s.io/minikube/pkg/drivers/kic/oci" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" - pkg_config "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/driver" @@ -94,9 +93,8 @@ func runDelete(cmd *cobra.Command, args []string) { if len(args) > 0 { exit.UsageT("Usage: minikube delete") } - profileFlag := viper.GetString(config.MachineProfile) - validProfiles, invalidProfiles, err := pkg_config.ListProfiles() + validProfiles, invalidProfiles, err := config.ListProfiles() if err != nil { glog.Warningf("'error loading profiles in minikube home %q: %v", localpath.MiniPath(), err) } @@ -112,11 +110,8 @@ func runDelete(cmd *cobra.Command, args []string) { } if deleteAll { - if profileFlag != constants.DefaultMachineName { - exit.UsageT("usage: minikube delete --all") - } delLabel := fmt.Sprintf("%s=%s", oci.CreatedByLabelKey, "true") - errs := oci.DeleteAllContainersByLabel(oci.Docker, delLabel) + errs := oci.DeleteContainersByLabel(oci.Docker, delLabel) if len(errs) > 0 { // it will error if there is no container to delete glog.Infof("error delete containers by label %q (might be okay): %+v", delLabel, err) } @@ -142,12 +137,13 @@ func runDelete(cmd *cobra.Command, args []string) { exit.UsageT("usage: minikube delete") } - profile, err := pkg_config.LoadProfile(profileFlag) + profileName := viper.GetString(config.ProfileName) + profile, err := config.LoadProfile(profileName) if err != nil { - out.ErrT(out.Meh, `"{{.name}}" profile does not exist, trying anyways.`, out.V{"name": profileFlag}) + out.ErrT(out.Meh, `"{{.name}}" profile does not exist, trying anyways.`, out.V{"name": profileName}) } - errs := DeleteProfiles([]*pkg_config.Profile{profile}) + errs := DeleteProfiles([]*config.Profile{profile}) if len(errs) > 0 { HandleDeletionErrors(errs) } @@ -168,7 +164,7 @@ func purgeMinikubeDirectory() { } // DeleteProfiles deletes one or more profiles -func DeleteProfiles(profiles []*pkg_config.Profile) []error { +func DeleteProfiles(profiles []*config.Profile) []error { var errs []error for _, profile := range profiles { err := deleteProfile(profile) @@ -189,11 +185,11 @@ func DeleteProfiles(profiles []*pkg_config.Profile) []error { return errs } -func deleteProfile(profile *pkg_config.Profile) error { - viper.Set(pkg_config.MachineProfile, profile.Name) +func deleteProfile(profile *config.Profile) error { + viper.Set(config.ProfileName, profile.Name) delLabel := fmt.Sprintf("%s=%s", oci.ProfileLabelKey, profile.Name) - errs := oci.DeleteAllContainersByLabel(oci.Docker, delLabel) + errs := oci.DeleteContainersByLabel(oci.Docker, delLabel) if errs != nil { // it will error if there is no container to delete glog.Infof("error deleting containers for %s (might be okay):\n%v", profile.Name, errs) } @@ -206,21 +202,20 @@ func deleteProfile(profile *pkg_config.Profile) error { if len(errs) > 0 { // it will not error if there is nothing to delete glog.Warningf("error pruning volume (might be okay):\n%v", errs) } - api, err := machine.NewAPIClient() if err != nil { delErr := profileDeletionErr(profile.Name, fmt.Sprintf("error getting client %v", err)) return DeletionError{Err: delErr, Errtype: Fatal} } defer api.Close() - cc, err := pkg_config.Load(profile.Name) - if err != nil && !pkg_config.IsNotExist(err) { + cc, err := config.Load(profile.Name) + if err != nil && !config.IsNotExist(err) { delErr := profileDeletionErr(profile.Name, fmt.Sprintf("error loading profile config: %v", err)) return DeletionError{Err: delErr, Errtype: MissingProfile} } if err == nil && driver.BareMetal(cc.Driver) { - if err := uninstallKubernetes(api, profile.Name, cc.KubernetesConfig, viper.GetString(cmdcfg.Bootstrapper), cc.Nodes[0].Name); err != nil { + if err := uninstallKubernetes(api, *cc, cc.Nodes[0], viper.GetString(cmdcfg.Bootstrapper)); err != nil { deletionError, ok := err.(DeletionError) if ok { delErr := profileDeletionErr(profile.Name, fmt.Sprintf("%v", err)) @@ -237,10 +232,11 @@ func deleteProfile(profile *pkg_config.Profile) error { if cc != nil { for _, n := range cc.Nodes { - if err = machine.DeleteHost(api, driver.MachineName(profile.Name, n.Name)); err != nil { + machineName := driver.MachineName(*cc, n) + if err = machine.DeleteHost(api, machineName); err != nil { switch errors.Cause(err).(type) { case mcnerror.ErrHostDoesNotExist: - glog.Infof("%s cluster does not exist. Proceeding ahead with cleanup.", profile.Name) + glog.Infof("Host %s does not exist. Proceeding ahead with cleanup.", machineName) default: out.T(out.FailureType, "Failed to delete cluster: {{.error}}", out.V{"error": err}) out.T(out.Notice, `You may need to manually remove the "{{.name}}" VM from your hypervisor`, out.V{"name": profile.Name}) @@ -252,8 +248,8 @@ func deleteProfile(profile *pkg_config.Profile) error { // In case DeleteHost didn't complete the job. deleteProfileDirectory(profile.Name) - if err := pkg_config.DeleteProfile(profile.Name); err != nil { - if pkg_config.IsNotExist(err) { + if err := config.DeleteProfile(profile.Name); err != nil { + if config.IsNotExist(err) { delErr := profileDeletionErr(profile.Name, fmt.Sprintf("\"%s\" profile does not exist", profile.Name)) return DeletionError{Err: delErr, Errtype: MissingProfile} } @@ -273,17 +269,17 @@ func deleteContext(machineName string) error { return DeletionError{Err: fmt.Errorf("update config: %v", err), Errtype: Fatal} } - if err := cmdcfg.Unset(pkg_config.MachineProfile); err != nil { + if err := cmdcfg.Unset(config.ProfileName); err != nil { return DeletionError{Err: fmt.Errorf("unset minikube profile: %v", err), Errtype: Fatal} } return nil } -func deleteInvalidProfile(profile *pkg_config.Profile) []error { +func deleteInvalidProfile(profile *config.Profile) []error { out.T(out.DeletingHost, "Trying to delete invalid profile {{.profile}}", out.V{"profile": profile.Name}) var errs []error - pathToProfile := pkg_config.ProfileFolderPath(profile.Name, localpath.MiniPath()) + pathToProfile := config.ProfileFolderPath(profile.Name, localpath.MiniPath()) if _, err := os.Stat(pathToProfile); !os.IsNotExist(err) { err := os.RemoveAll(pathToProfile) if err != nil { @@ -305,14 +301,14 @@ func profileDeletionErr(profileName string, additionalInfo string) error { return fmt.Errorf("error deleting profile \"%s\": %s", profileName, additionalInfo) } -func uninstallKubernetes(api libmachine.API, profile string, kc pkg_config.KubernetesConfig, bsName string, nodeName string) error { - out.T(out.Resetting, "Uninstalling Kubernetes {{.kubernetes_version}} using {{.bootstrapper_name}} ...", out.V{"kubernetes_version": kc.KubernetesVersion, "bootstrapper_name": bsName}) - clusterBootstrapper, err := cluster.Bootstrapper(api, bsName, profile, nodeName) +func uninstallKubernetes(api libmachine.API, cc config.ClusterConfig, n config.Node, bsName string) error { + out.T(out.Resetting, "Uninstalling Kubernetes {{.kubernetes_version}} using {{.bootstrapper_name}} ...", out.V{"kubernetes_version": cc.KubernetesConfig.KubernetesVersion, "bootstrapper_name": bsName}) + clusterBootstrapper, err := cluster.Bootstrapper(api, bsName, cc, n) if err != nil { return DeletionError{Err: fmt.Errorf("unable to get bootstrapper: %v", err), Errtype: Fatal} } - host, err := machine.CheckIfHostExistsAndLoad(api, profile) + host, err := machine.CheckIfHostExistsAndLoad(api, driver.MachineName(cc, n)) if err != nil { exit.WithError("Error getting host", err) } @@ -321,7 +317,7 @@ func uninstallKubernetes(api libmachine.API, profile string, kc pkg_config.Kuber exit.WithError("Failed to get command runner", err) } - cr, err := cruntime.New(cruntime.Config{Type: kc.ContainerRuntime, Runner: r}) + cr, err := cruntime.New(cruntime.Config{Type: cc.KubernetesConfig.ContainerRuntime, Runner: r}) if err != nil { exit.WithError("Failed runtime", err) } @@ -332,7 +328,7 @@ func uninstallKubernetes(api libmachine.API, profile string, kc pkg_config.Kuber glog.Errorf("unpause failed: %v", err) } - if err = clusterBootstrapper.DeleteCluster(kc); err != nil { + if err = clusterBootstrapper.DeleteCluster(cc.KubernetesConfig); err != nil { return DeletionError{Err: fmt.Errorf("failed to delete cluster: %v", err), Errtype: Fatal} } return nil diff --git a/cmd/minikube/cmd/delete_test.go b/cmd/minikube/cmd/delete_test.go index fddfc201da..de16ed9107 100644 --- a/cmd/minikube/cmd/delete_test.go +++ b/cmd/minikube/cmd/delete_test.go @@ -141,7 +141,7 @@ func TestDeleteProfile(t *testing.T) { t.Errorf("machines mismatch (-want +got):\n%s", diff) } - viper.Set(config.MachineProfile, "") + viper.Set(config.ProfileName, "") }) } } @@ -211,5 +211,5 @@ func TestDeleteAllProfiles(t *testing.T) { t.Errorf("Did not delete all machines, remaining: %v", afterMachines) } - viper.Set(config.MachineProfile, "") + viper.Set(config.ProfileName, "") } diff --git a/cmd/minikube/cmd/docker-env.go b/cmd/minikube/cmd/docker-env.go index f43e96dfa6..d7d532fb2e 100644 --- a/cmd/minikube/cmd/docker-env.go +++ b/cmd/minikube/cmd/docker-env.go @@ -143,79 +143,82 @@ var dockerEnvCmd = &cobra.Command{ } defer api.Close() - profile := viper.GetString(config.MachineProfile) + profile := viper.GetString(config.ProfileName) cc, err := config.Load(profile) if err != nil { exit.WithError("Error getting config", err) } - host, err := machine.CheckIfHostExistsAndLoad(api, cc.Name) - if err != nil { - exit.WithError("Error getting host", err) - } - if host.Driver.DriverName() == driver.None { - exit.UsageT(`'none' driver does not support 'minikube docker-env' command`) - } - - hostSt, err := machine.GetHostStatus(api, cc.Name) - if err != nil { - exit.WithError("Error getting host status", err) - } - if hostSt != state.Running.String() { - exit.WithCodeT(exit.Unavailable, `'{{.profile}}' is not running`, out.V{"profile": profile}) - } - ok, err := isDockerActive(host.Driver) - if err != nil { - exit.WithError("Error getting service status", err) - } - - if !ok { - exit.WithCodeT(exit.Unavailable, `The docker service within '{{.profile}}' is not active`, out.V{"profile": profile}) - } - - hostIP, err := host.Driver.GetIP() - if err != nil { - exit.WithError("Error getting host IP", err) - } - - sh := shell.EnvConfig{ - Shell: shell.ForceShell, - } - - port := constants.DockerDaemonPort - if driver.IsKIC(host.DriverName) { // for kic we need to find what port docker/podman chose for us - hostIP = oci.DefaultBindIPV4 - port, err = oci.HostPortBinding(host.DriverName, profile, port) + for _, n := range cc.Nodes { + machineName := driver.MachineName(*cc, n) + host, err := machine.CheckIfHostExistsAndLoad(api, machineName) if err != nil { - exit.WithCodeT(exit.Failure, "Error getting port binding for '{{.driver_name}} driver: {{.error}}", out.V{"driver_name": host.DriverName, "error": err}) + exit.WithError("Error getting host", err) + } + if host.Driver.DriverName() == driver.None { + exit.UsageT(`'none' driver does not support 'minikube docker-env' command`) } - } - ec := DockerEnvConfig{ - EnvConfig: sh, - profile: profile, - driver: host.DriverName, - hostIP: hostIP, - port: port, - certsDir: localpath.MakeMiniPath("certs"), - noProxy: noProxy, - } - - if ec.Shell == "" { - ec.Shell, err = shell.Detect() + hostSt, err := machine.GetHostStatus(api, machineName) if err != nil { - exit.WithError("Error detecting shell", err) + exit.WithError("Error getting host status", err) } - } - - if dockerUnset { - if err := dockerUnsetScript(ec, os.Stdout); err != nil { - exit.WithError("Error generating unset output", err) + if hostSt != state.Running.String() { + exit.WithCodeT(exit.Unavailable, `'{{.profile}}' is not running`, out.V{"profile": profile}) + } + ok, err := isDockerActive(host.Driver) + if err != nil { + exit.WithError("Error getting service status", err) } - return - } - if err := dockerSetScript(ec, os.Stdout); err != nil { - exit.WithError("Error generating set output", err) + if !ok { + exit.WithCodeT(exit.Unavailable, `The docker service within '{{.profile}}' is not active`, out.V{"profile": profile}) + } + + hostIP, err := host.Driver.GetIP() + if err != nil { + exit.WithError("Error getting host IP", err) + } + + sh := shell.EnvConfig{ + Shell: shell.ForceShell, + } + + port := constants.DockerDaemonPort + if driver.IsKIC(host.DriverName) { // for kic we need to find what port docker/podman chose for us + hostIP = oci.DefaultBindIPV4 + port, err = oci.HostPortBinding(host.DriverName, profile, port) + if err != nil { + exit.WithCodeT(exit.Failure, "Error getting port binding for '{{.driver_name}} driver: {{.error}}", out.V{"driver_name": host.DriverName, "error": err}) + } + } + + ec := DockerEnvConfig{ + EnvConfig: sh, + profile: profile, + driver: host.DriverName, + hostIP: hostIP, + port: port, + certsDir: localpath.MakeMiniPath("certs"), + noProxy: noProxy, + } + + if ec.Shell == "" { + ec.Shell, err = shell.Detect() + if err != nil { + exit.WithError("Error detecting shell", err) + } + } + + if dockerUnset { + if err := dockerUnsetScript(ec, os.Stdout); err != nil { + exit.WithError("Error generating unset output", err) + } + return + } + + if err := dockerSetScript(ec, os.Stdout); err != nil { + exit.WithError("Error generating set output", err) + } } }, } diff --git a/cmd/minikube/cmd/ip.go b/cmd/minikube/cmd/ip.go index a6b607eb12..466323b4a4 100644 --- a/cmd/minikube/cmd/ip.go +++ b/cmd/minikube/cmd/ip.go @@ -40,24 +40,26 @@ var ipCmd = &cobra.Command{ } defer api.Close() - cc, err := config.Load(viper.GetString(config.MachineProfile)) + cc, err := config.Load(viper.GetString(config.ProfileName)) if err != nil { exit.WithError("Error getting config", err) } - machineName := driver.MachineName(cc.Name, cc.Nodes[0].Name) - host, err := api.Load(machineName) - if err != nil { - switch err := errors.Cause(err).(type) { - case mcnerror.ErrHostDoesNotExist: - exit.WithCodeT(exit.NoInput, `"{{.profile_name}}" host does not exist, unable to show an IP`, out.V{"profile_name": machineName}) - default: - exit.WithError("Error getting host", err) + for _, n := range cc.Nodes { + machineName := driver.MachineName(*cc, n) + host, err := api.Load(machineName) + if err != nil { + switch err := errors.Cause(err).(type) { + case mcnerror.ErrHostDoesNotExist: + exit.WithCodeT(exit.NoInput, `"{{.profile_name}}" host does not exist, unable to show an IP`, out.V{"profile_name": cc.Name}) + default: + exit.WithError("Error getting host", err) + } } + ip, err := host.Driver.GetIP() + if err != nil { + exit.WithError("Error getting IP", err) + } + out.Ln(ip) } - ip, err := host.Driver.GetIP() - if err != nil { - exit.WithError("Error getting IP", err) - } - out.Ln(ip) }, } diff --git a/cmd/minikube/cmd/kubectl.go b/cmd/minikube/cmd/kubectl.go index 342b9b283d..e5520d8153 100644 --- a/cmd/minikube/cmd/kubectl.go +++ b/cmd/minikube/cmd/kubectl.go @@ -49,7 +49,7 @@ minikube kubectl -- get pods --namespace kube-system`, } defer api.Close() - cc, err := config.Load(viper.GetString(config.MachineProfile)) + cc, err := config.Load(viper.GetString(config.ProfileName)) if err != nil && !config.IsNotExist(err) { out.ErrLn("Error loading profile config: %v", err) } diff --git a/cmd/minikube/cmd/logs.go b/cmd/minikube/cmd/logs.go index 7b6ff5f757..6e75882302 100644 --- a/cmd/minikube/cmd/logs.go +++ b/cmd/minikube/cmd/logs.go @@ -23,9 +23,11 @@ import ( "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/logs" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/node" ) const ( @@ -34,6 +36,7 @@ const ( ) var ( + nodeName string // followLogs triggers tail -f mode followLogs bool // numberOfLines is how many lines to output, set via -n @@ -48,18 +51,33 @@ var logsCmd = &cobra.Command{ Short: "Gets the logs of the running instance, used for debugging minikube, not user code.", Long: `Gets the logs of the running instance, used for debugging minikube, not user code.`, Run: func(cmd *cobra.Command, args []string) { - cfg, err := config.Load(viper.GetString(config.MachineProfile)) + cfg, err := config.Load(viper.GetString(config.ProfileName)) if err != nil { exit.WithError("Error getting config", err) } + if nodeName == "" { + cp, err := config.PrimaryControlPlane(*cfg) + if err != nil { + exit.WithError("Error getting primary control plane", err) + } + nodeName = cp.Name + } + + n, _, err := node.Retrieve(cfg, nodeName) + if err != nil { + exit.WithError("Error retrieving node", err) + } + + machineName := driver.MachineName(*cfg, *n) + api, err := machine.NewAPIClient() if err != nil { exit.WithError("Error getting client", err) } defer api.Close() - h, err := api.Load(cfg.Name) + h, err := api.Load(machineName) if err != nil { exit.WithError("api load", err) } @@ -67,7 +85,7 @@ var logsCmd = &cobra.Command{ if err != nil { exit.WithError("command runner", err) } - bs, err := cluster.Bootstrapper(api, viper.GetString(cmdcfg.Bootstrapper), viper.GetString(config.MachineProfile), viper.GetString(config.MachineProfile)) + bs, err := cluster.Bootstrapper(api, viper.GetString(cmdcfg.Bootstrapper), *cfg, *n) if err != nil { exit.WithError("Error getting cluster bootstrapper", err) } @@ -99,4 +117,5 @@ func init() { logsCmd.Flags().BoolVarP(&followLogs, "follow", "f", false, "Show only the most recent journal entries, and continuously print new entries as they are appended to the journal.") logsCmd.Flags().BoolVar(&showProblems, "problems", false, "Show only log entries which point to known problems") logsCmd.Flags().IntVarP(&numberOfLines, "length", "n", 60, "Number of lines back to go within the log") + logsCmd.Flags().StringVar(&nodeName, "node", "", "The node to get logs from. Defaults to the primary control plane.") } diff --git a/cmd/minikube/cmd/mount.go b/cmd/minikube/cmd/mount.go index 0ca2883ff6..9f8a0e8a89 100644 --- a/cmd/minikube/cmd/mount.go +++ b/cmd/minikube/cmd/mount.go @@ -104,11 +104,16 @@ var mountCmd = &cobra.Command{ exit.WithError("Error getting client", err) } defer api.Close() - cc, err := config.Load(viper.GetString(config.MachineProfile)) + cc, err := config.Load(viper.GetString(config.ProfileName)) if err != nil { exit.WithError("Error getting config", err) } - host, err := api.Load(cc.Name) + + cp, err := config.PrimaryControlPlane(*cc) + if err != nil { + exit.WithError("Error getting primary cp", err) + } + host, err := api.Load(driver.MachineName(*cc, cp)) if err != nil { exit.WithError("Error loading api", err) } diff --git a/cmd/minikube/cmd/node_add.go b/cmd/minikube/cmd/node_add.go index 8cb836edea..3995e7a6d7 100644 --- a/cmd/minikube/cmd/node_add.go +++ b/cmd/minikube/cmd/node_add.go @@ -17,7 +17,7 @@ limitations under the License. package cmd import ( - "strconv" + "fmt" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -29,39 +29,31 @@ import ( ) var ( - nodeName string - cp bool - worker bool + cp bool + worker bool ) var nodeAddCmd = &cobra.Command{ Use: "add", Short: "Adds a node to the given cluster.", Long: "Adds a node to the given cluster config, and starts it.", Run: func(cmd *cobra.Command, args []string) { - profile := viper.GetString(config.MachineProfile) - mc, err := config.Load(profile) + profile := viper.GetString(config.ProfileName) + cc, err := config.Load(profile) if err != nil { exit.WithError("Error getting config", err) } - name := nodeName - if nodeName == "" { - name = profile + strconv.Itoa(len(mc.Nodes)+1) - } - _, _, err = node.Retrieve(mc, name) - if err == nil { - exit.WithCodeT(100, "{{.nodeName}} already exists in cluster {{.cluster}}. Choose a different name.", out.V{"nodeName": name, "cluster": mc.Name}) - } + + //name := profile + strconv.Itoa(len(mc.Nodes)+1) + name := fmt.Sprintf("m%d", len(cc.Nodes)+1) + out.T(out.Happy, "Adding node {{.name}} to cluster {{.cluster}}", out.V{"name": name, "cluster": profile}) - // TODO: Deal with parameters better. Ideally we should be able to acceot any node-specific minikube start params here. - n := config.Node{ - Name: name, - Worker: worker, - ControlPlane: cp, - KubernetesVersion: mc.KubernetesConfig.KubernetesVersion, + n, err := node.Add(cc, name, cp, worker, "", profile) + if err != nil { + exit.WithError("Error adding node to cluster", err) } - err = node.Add(mc, n) + _, err = node.Start(*cc, *n, false, nil) if err != nil { exit.WithError("Error adding node to cluster", err) } @@ -71,7 +63,6 @@ var nodeAddCmd = &cobra.Command{ } func init() { - nodeAddCmd.Flags().StringVar(&nodeName, "name", "", "The name of the node to add.") nodeAddCmd.Flags().BoolVar(&cp, "control-plane", false, "If true, the node added will also be a control plane in addition to a worker.") nodeAddCmd.Flags().BoolVar(&worker, "worker", true, "If true, the added node will be marked for work. Defaults to true.") //We should figure out which of these flags to actually import diff --git a/cmd/minikube/cmd/node_delete.go b/cmd/minikube/cmd/node_delete.go index 33d6ca6660..8f43749a27 100644 --- a/cmd/minikube/cmd/node_delete.go +++ b/cmd/minikube/cmd/node_delete.go @@ -36,7 +36,7 @@ var nodeDeleteCmd = &cobra.Command{ } name := args[0] - profile := viper.GetString(config.MachineProfile) + profile := viper.GetString(config.ProfileName) out.T(out.DeletingHost, "Deleting node {{.name}} from cluster {{.cluster}}", out.V{"name": name, "cluster": profile}) cc, err := config.Load(profile) diff --git a/cmd/minikube/cmd/node_start.go b/cmd/minikube/cmd/node_start.go index 9d17ab1b7f..92f866f99e 100644 --- a/cmd/minikube/cmd/node_start.go +++ b/cmd/minikube/cmd/node_start.go @@ -50,7 +50,7 @@ var nodeStartCmd = &cobra.Command{ os.Exit(0) } - cc, err := config.Load(viper.GetString(config.MachineProfile)) + cc, err := config.Load(viper.GetString(config.ProfileName)) if err != nil { exit.WithError("loading config", err) } diff --git a/cmd/minikube/cmd/node_stop.go b/cmd/minikube/cmd/node_stop.go index 37afecdddb..e2a37573b8 100644 --- a/cmd/minikube/cmd/node_stop.go +++ b/cmd/minikube/cmd/node_stop.go @@ -18,8 +18,12 @@ package cmd import ( "github.com/spf13/cobra" + "github.com/spf13/viper" + "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/node" "k8s.io/minikube/pkg/minikube/out" ) @@ -39,7 +43,19 @@ var nodeStopCmd = &cobra.Command{ exit.WithError("creating api client", err) } - err = machine.StopHost(api, name) + cc, err := config.Load(viper.GetString(config.ProfileName)) + if err != nil { + exit.WithError("getting config", err) + } + + n, _, err := node.Retrieve(cc, name) + if err != nil { + exit.WithError("retrieving node", err) + } + + machineName := driver.MachineName(*cc, *n) + + err = machine.StopHost(api, machineName) if err != nil { out.FatalT("Failed to stop node {{.name}}", out.V{"name": name}) } diff --git a/cmd/minikube/cmd/pause.go b/cmd/minikube/cmd/pause.go index 5f3fadb219..7cbc3855d8 100644 --- a/cmd/minikube/cmd/pause.go +++ b/cmd/minikube/cmd/pause.go @@ -27,6 +27,7 @@ import ( "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" @@ -45,7 +46,7 @@ var pauseCmd = &cobra.Command{ } func runPause(cmd *cobra.Command, args []string) { - cname := viper.GetString(config.MachineProfile) + cname := viper.GetString(config.ProfileName) api, err := machine.NewAPIClient() if err != nil { exit.WithError("Error getting client", err) @@ -63,37 +64,40 @@ func runPause(cmd *cobra.Command, args []string) { } glog.Infof("config: %+v", cc) - host, err := machine.CheckIfHostExistsAndLoad(api, cname) - if err != nil { - exit.WithError("Error getting host", err) - } - r, err := machine.CommandRunner(host) - if err != nil { - exit.WithError("Failed to get command runner", err) - } + for _, n := range cc.Nodes { + host, err := machine.CheckIfHostExistsAndLoad(api, driver.MachineName(*cc, n)) + if err != nil { + exit.WithError("Error getting host", err) + } - cr, err := cruntime.New(cruntime.Config{Type: cc.KubernetesConfig.ContainerRuntime, Runner: r}) - if err != nil { - exit.WithError("Failed runtime", err) - } + r, err := machine.CommandRunner(host) + if err != nil { + exit.WithError("Failed to get command runner", err) + } - glog.Infof("namespaces: %v keys: %v", namespaces, viper.AllSettings()) - if allNamespaces { - namespaces = nil //all - } else if len(namespaces) == 0 { - exit.WithCodeT(exit.BadUsage, "Use -A to specify all namespaces") - } + cr, err := cruntime.New(cruntime.Config{Type: cc.KubernetesConfig.ContainerRuntime, Runner: r}) + if err != nil { + exit.WithError("Failed runtime", err) + } - ids, err := cluster.Pause(cr, r, namespaces) - if err != nil { - exit.WithError("Pause", err) - } + glog.Infof("namespaces: %v keys: %v", namespaces, viper.AllSettings()) + if allNamespaces { + namespaces = nil //all + } else if len(namespaces) == 0 { + exit.WithCodeT(exit.BadUsage, "Use -A to specify all namespaces") + } - if namespaces == nil { - out.T(out.Unpause, "Paused kubelet and {{.count}} containers", out.V{"count": len(ids)}) - } else { - out.T(out.Unpause, "Paused kubelet and {{.count}} containers in: {{.namespaces}}", out.V{"count": len(ids), "namespaces": strings.Join(namespaces, ", ")}) + ids, err := cluster.Pause(cr, r, namespaces) + if err != nil { + exit.WithError("Pause", err) + } + + if namespaces == nil { + out.T(out.Unpause, "Paused kubelet and {{.count}} containers", out.V{"count": len(ids)}) + } else { + out.T(out.Unpause, "Paused kubelet and {{.count}} containers in: {{.namespaces}}", out.V{"count": len(ids), "namespaces": strings.Join(namespaces, ", ")}) + } } } diff --git a/cmd/minikube/cmd/podman-env.go b/cmd/minikube/cmd/podman-env.go index fe77feb6c7..1240d08c8c 100644 --- a/cmd/minikube/cmd/podman-env.go +++ b/cmd/minikube/cmd/podman-env.go @@ -114,66 +114,69 @@ var podmanEnvCmd = &cobra.Command{ } defer api.Close() - profile := viper.GetString(config.MachineProfile) + profile := viper.GetString(config.ProfileName) cc, err := config.Load(profile) if err != nil { exit.WithError("Error getting config", err) } - host, err := machine.CheckIfHostExistsAndLoad(api, cc.Name) - if err != nil { - exit.WithError("Error getting host", err) - } - if host.Driver.DriverName() == driver.None { - exit.UsageT(`'none' driver does not support 'minikube podman-env' command`) - } - - hostSt, err := machine.GetHostStatus(api, cc.Name) - if err != nil { - exit.WithError("Error getting host status", err) - } - if hostSt != state.Running.String() { - exit.WithCodeT(exit.Unavailable, `'{{.profile}}' is not running`, out.V{"profile": profile}) - } - ok, err := isPodmanAvailable(host) - if err != nil { - exit.WithError("Error getting service status", err) - } - - if !ok { - exit.WithCodeT(exit.Unavailable, `The podman service within '{{.profile}}' is not active`, out.V{"profile": profile}) - } - - client, err := createExternalSSHClient(host.Driver) - if err != nil { - exit.WithError("Error getting ssh client", err) - } - - sh := shell.EnvConfig{ - Shell: shell.ForceShell, - } - ec := PodmanEnvConfig{ - EnvConfig: sh, - profile: profile, - driver: host.DriverName, - client: client, - } - - if ec.Shell == "" { - ec.Shell, err = shell.Detect() + for _, n := range cc.Nodes { + machineName := driver.MachineName(*cc, n) + host, err := machine.CheckIfHostExistsAndLoad(api, machineName) if err != nil { - exit.WithError("Error detecting shell", err) + exit.WithError("Error getting host", err) } - } - - if podmanUnset { - if err := podmanUnsetScript(ec, os.Stdout); err != nil { - exit.WithError("Error generating unset output", err) + if host.Driver.DriverName() == driver.None { + exit.UsageT(`'none' driver does not support 'minikube podman-env' command`) } - return - } - if err := podmanSetScript(ec, os.Stdout); err != nil { - exit.WithError("Error generating set output", err) + hostSt, err := machine.GetHostStatus(api, machineName) + if err != nil { + exit.WithError("Error getting host status", err) + } + if hostSt != state.Running.String() { + exit.WithCodeT(exit.Unavailable, `'{{.profile}}' is not running`, out.V{"profile": profile}) + } + ok, err := isPodmanAvailable(host) + if err != nil { + exit.WithError("Error getting service status", err) + } + + if !ok { + exit.WithCodeT(exit.Unavailable, `The podman service within '{{.profile}}' is not active`, out.V{"profile": profile}) + } + + client, err := createExternalSSHClient(host.Driver) + if err != nil { + exit.WithError("Error getting ssh client", err) + } + + sh := shell.EnvConfig{ + Shell: shell.ForceShell, + } + ec := PodmanEnvConfig{ + EnvConfig: sh, + profile: profile, + driver: host.DriverName, + client: client, + } + + if ec.Shell == "" { + ec.Shell, err = shell.Detect() + if err != nil { + exit.WithError("Error detecting shell", err) + } + } + + if podmanUnset { + if err := podmanUnsetScript(ec, os.Stdout); err != nil { + exit.WithError("Error generating unset output", err) + } + return + } + + if err := podmanSetScript(ec, os.Stdout); err != nil { + exit.WithError("Error generating set output", err) + } } }, } diff --git a/cmd/minikube/cmd/root.go b/cmd/minikube/cmd/root.go index a92e080f8d..febfadcc09 100644 --- a/cmd/minikube/cmd/root.go +++ b/cmd/minikube/cmd/root.go @@ -156,7 +156,7 @@ func setFlagsUsingViper() { func init() { translate.DetermineLocale() - RootCmd.PersistentFlags().StringP(config.MachineProfile, "p", constants.DefaultMachineName, `The name of the minikube VM being used. This can be set to allow having multiple instances of minikube independently.`) + RootCmd.PersistentFlags().StringP(config.ProfileName, "p", constants.DefaultClusterName, `The name of the minikube VM being used. This can be set to allow having multiple instances of minikube independently.`) RootCmd.PersistentFlags().StringP(configCmd.Bootstrapper, "b", "kubeadm", "The name of the cluster bootstrapper that will set up the kubernetes cluster.") groups := templates.CommandGroups{ diff --git a/cmd/minikube/cmd/service.go b/cmd/minikube/cmd/service.go index 0fabfbc32b..19827913d9 100644 --- a/cmd/minikube/cmd/service.go +++ b/cmd/minikube/cmd/service.go @@ -20,18 +20,29 @@ import ( "fmt" "net/url" "os" + "os/signal" + "path/filepath" + "runtime" + "strconv" + "strings" "text/template" + "time" "github.com/golang/glog" "github.com/pkg/browser" "github.com/spf13/cobra" "github.com/spf13/viper" + "k8s.io/minikube/pkg/drivers/kic/oci" + "k8s.io/minikube/pkg/minikube/config" pkg_config "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/service" + "k8s.io/minikube/pkg/minikube/tunnel/kic" ) const defaultServiceFormatTemplate = "http://{{.IP}}:{{.Port}}" @@ -72,33 +83,31 @@ var serviceCmd = &cobra.Command{ } defer api.Close() - profileName := viper.GetString(pkg_config.MachineProfile) - if !machine.IsHostRunning(api, profileName) { + profileName := viper.GetString(pkg_config.ProfileName) + cfg, err := config.Load(profileName) + if err != nil { + exit.WithError("Error getting config", err) + } + cp, err := config.PrimaryControlPlane(*cfg) + if err != nil { + exit.WithError("Error getting control plane", err) + } + machineName := driver.MachineName(*cfg, cp) + if !machine.IsHostRunning(api, machineName) { os.Exit(1) } + if runtime.GOOS == "darwin" && cfg.Driver == oci.Docker { + startKicServiceTunnel(svc, cfg.Name) + return + } + urls, err := service.WaitForService(api, namespace, svc, serviceURLTemplate, serviceURLMode, https, wait, interval) if err != nil { exit.WithError("Error opening service", err) } - for _, u := range urls { - _, err := url.Parse(u) - if err != nil { - glog.Warningf("failed to parse url %q: %v (will not open)", u, err) - out.String(fmt.Sprintf("%s\n", u)) - continue - } - - if serviceURLMode { - out.String(fmt.Sprintf("%s\n", u)) - continue - } - out.T(out.Celebrate, "Opening service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": svc}) - if err := browser.OpenURL(u); err != nil { - exit.WithError(fmt.Sprintf("open url failed: %s", u), err) - } - } + openURLs(svc, urls) }, } @@ -112,3 +121,63 @@ func init() { serviceCmd.PersistentFlags().StringVar(&serviceURLFormat, "format", defaultServiceFormatTemplate, "Format to output service URL in. This format will be applied to each url individually and they will be printed one at a time.") } + +func startKicServiceTunnel(svc, configName string) { + ctrlC := make(chan os.Signal, 1) + signal.Notify(ctrlC, os.Interrupt) + + clientset, err := service.K8s.GetClientset(1 * time.Second) + if err != nil { + exit.WithError("error creating clientset", err) + } + + port, err := oci.HostPortBinding(oci.Docker, configName, 22) + if err != nil { + exit.WithError("error getting ssh port", err) + } + sshPort := strconv.Itoa(port) + sshKey := filepath.Join(localpath.MiniPath(), "machines", configName, "id_rsa") + + serviceTunnel := kic.NewServiceTunnel(sshPort, sshKey, clientset.CoreV1()) + urls, err := serviceTunnel.Start(svc, namespace) + if err != nil { + exit.WithError("error starting tunnel", err) + } + + // wait for tunnel to come up + time.Sleep(1 * time.Second) + + data := [][]string{{namespace, svc, "", strings.Join(urls, "\n")}} + service.PrintServiceList(os.Stdout, data) + + openURLs(svc, urls) + out.T(out.WarningType, "Because you are using docker driver on Mac, the terminal needs to be open to run it.") + + <-ctrlC + + err = serviceTunnel.Stop() + if err != nil { + exit.WithError("error stopping tunnel", err) + } +} + +func openURLs(svc string, urls []string) { + for _, u := range urls { + _, err := url.Parse(u) + if err != nil { + glog.Warningf("failed to parse url %q: %v (will not open)", u, err) + out.String(fmt.Sprintf("%s\n", u)) + continue + } + + if serviceURLMode { + out.String(fmt.Sprintf("%s\n", u)) + continue + } + + out.T(out.Celebrate, "Opening service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": svc}) + if err := browser.OpenURL(u); err != nil { + exit.WithError(fmt.Sprintf("open url failed: %s", u), err) + } + } +} diff --git a/cmd/minikube/cmd/service_list.go b/cmd/minikube/cmd/service_list.go index ad1903a4b8..446b6c65bc 100644 --- a/cmd/minikube/cmd/service_list.go +++ b/cmd/minikube/cmd/service_list.go @@ -18,10 +18,16 @@ package cmd import ( "os" + "runtime" "strings" "github.com/spf13/cobra" + "github.com/spf13/viper" core "k8s.io/api/core/v1" + "k8s.io/minikube/pkg/drivers/kic/oci" + "k8s.io/minikube/pkg/minikube/config" + pkg_config "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" @@ -41,6 +47,18 @@ var serviceListCmd = &cobra.Command{ exit.WithError("Error getting client", err) } defer api.Close() + profileName := viper.GetString(pkg_config.ProfileName) + cfg, err := config.Load(profileName) + if err != nil { + exit.WithError("Error getting config", err) + } + cp, err := config.PrimaryControlPlane(*cfg) + if err != nil { + exit.WithError("Error getting primary control plane", err) + } + if !machine.IsHostRunning(api, driver.MachineName(*cfg, cp)) { + exit.WithCodeT(exit.Unavailable, "profile {{.name}} is not running.", out.V{"name": profileName}) + } serviceURLs, err := service.GetServiceURLs(api, serviceListNamespace, serviceURLTemplate) if err != nil { out.FatalT("Failed to get service URL: {{.error}}", out.V{"error": err}) @@ -53,9 +71,15 @@ var serviceListCmd = &cobra.Command{ if len(serviceURL.URLs) == 0 { data = append(data, []string{serviceURL.Namespace, serviceURL.Name, "No node port"}) } else { - data = append(data, []string{serviceURL.Namespace, serviceURL.Name, strings.Join(serviceURL.URLs, "\n")}) - } + serviceURLs := strings.Join(serviceURL.URLs, "\n") + // if we are running Docker on OSX we empty the internal service URLs + if runtime.GOOS == "darwin" && cfg.Driver == oci.Docker { + serviceURLs = "" + } + + data = append(data, []string{serviceURL.Namespace, serviceURL.Name, "", serviceURLs}) + } } service.PrintServiceList(os.Stdout, data) diff --git a/cmd/minikube/cmd/ssh-key.go b/cmd/minikube/cmd/ssh-key.go index 223703f82d..61d2c441a8 100644 --- a/cmd/minikube/cmd/ssh-key.go +++ b/cmd/minikube/cmd/ssh-key.go @@ -33,7 +33,7 @@ var sshKeyCmd = &cobra.Command{ Short: "Retrieve the ssh identity key path of the specified cluster", Long: "Retrieve the ssh identity key path of the specified cluster.", Run: func(cmd *cobra.Command, args []string) { - cc, err := config.Load(viper.GetString(config.MachineProfile)) + cc, err := config.Load(viper.GetString(config.ProfileName)) if err != nil { exit.WithError("Getting machine config failed", err) } diff --git a/cmd/minikube/cmd/ssh.go b/cmd/minikube/cmd/ssh.go index 2ae2e5febd..9da3698ba9 100644 --- a/cmd/minikube/cmd/ssh.go +++ b/cmd/minikube/cmd/ssh.go @@ -27,9 +27,14 @@ import ( "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/node" "k8s.io/minikube/pkg/minikube/out" ) +var ( + nativeSSHClient bool +) + // sshCmd represents the docker-ssh command var sshCmd = &cobra.Command{ Use: "ssh", @@ -41,32 +46,34 @@ var sshCmd = &cobra.Command{ exit.WithError("Error getting client", err) } defer api.Close() - cc, err := config.Load(viper.GetString(config.MachineProfile)) + cc, err := config.Load(viper.GetString(config.ProfileName)) if err != nil { exit.WithError("Error getting config", err) } - + var n *config.Node if nodeName == "" { cp, err := config.PrimaryControlPlane(*cc) if err != nil { exit.WithError("Getting primary control plane", err) } - nodeName = cp.Name + n = &cp + } else { + n = node.Retrieve(cc, nodeName) } - host, err := machine.CheckIfHostExistsAndLoad(api, driver.MachineName(cc.Name, nodeName)) + host, err := machine.CheckIfHostExistsAndLoad(api, driver.MachineName(*cc, *n)) if err != nil { exit.WithError("Error getting host", err) } if host.Driver.DriverName() == driver.None { exit.UsageT("'none' driver does not support 'minikube ssh' command") } - if viper.GetBool(nativeSSH) { + if nativeSSHClient { ssh.SetDefaultClient(ssh.Native) } else { ssh.SetDefaultClient(ssh.External) } - err = machine.CreateSSHShell(api, driver.MachineName(cc.Name, nodeName), args) + err = machine.CreateSSHShell(api, *cc, cp, args) if err != nil { // This is typically due to a non-zero exit code, so no need for flourish. out.ErrLn("ssh: %v", err) diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 0db8d68826..0fd8f1c0c0 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -47,6 +47,7 @@ import ( "k8s.io/minikube/pkg/minikube/config" "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/exit" "k8s.io/minikube/pkg/minikube/kubeconfig" @@ -154,8 +155,8 @@ func initMinikubeFlags() { startCmd.Flags().String(memory, defaultMemorySize, "Amount of RAM allocated to the minikube VM (format: [], where unit = b, k, m or g).") startCmd.Flags().String(humanReadableDiskSize, defaultDiskSize, "Disk size allocated to the minikube VM (format: [], where unit = b, k, m or g).") startCmd.Flags().Bool(downloadOnly, false, "If true, only download and cache files for later use - don't install or start anything.") - startCmd.Flags().Bool(cacheImages, true, "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --vm-driver=none.") - startCmd.Flags().String(isoURL, constants.DefaultISOURL, "Location of the minikube iso.") + startCmd.Flags().Bool(cacheImages, true, "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.") + startCmd.Flags().StringSlice(isoURL, download.DefaultISOURLs(), "Locations to fetch the minikube ISO from.") startCmd.Flags().Bool(keepContext, false, "This will keep the existing kubectl context and will create a minikube context.") startCmd.Flags().Bool(embedCerts, false, "if true, will embed the certs in kubeconfig.") startCmd.Flags().String(containerRuntime, "docker", "The container runtime to be used (docker, crio, containerd).") @@ -191,7 +192,8 @@ func initKubernetesFlags() { // initDriverFlags inits the commandline flags for vm drivers func initDriverFlags() { - startCmd.Flags().String("vm-driver", "", fmt.Sprintf("Driver is one of: %v (defaults to auto-detect)", driver.DisplaySupportedDrivers())) + startCmd.Flags().String("driver", "", fmt.Sprintf("Driver is one of: %v (defaults to auto-detect)", driver.DisplaySupportedDrivers())) + startCmd.Flags().String("vm-driver", "", "DEPRECATED, use `driver` instead.") startCmd.Flags().Bool(disableDriverMounts, false, "Disables the filesystem mounts provided by the hypervisors") // kvm2 @@ -288,7 +290,7 @@ func runStart(cmd *cobra.Command, args []string) { registryMirror = viper.GetStringSlice("registry_mirror") } - existing, err := config.Load(viper.GetString(config.MachineProfile)) + existing, err := config.Load(viper.GetString(config.ProfileName)) if err != nil && !config.IsNotExist(err) { exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err}) } @@ -322,7 +324,13 @@ func runStart(cmd *cobra.Command, args []string) { return } - cacheISO(&mc, driverName) + if !driver.BareMetal(driverName) && !driver.IsKIC(driverName) { + url, err := download.ISO(viper.GetStringSlice(isoURL)) + if err != nil { + exit.WithError("Failed to cache ISO", err) + } + mc.MinikubeISO = url + } if viper.GetBool(nativeSSH) { ssh.SetDefaultClient(ssh.Native) @@ -383,18 +391,10 @@ func updateDriver(driverName string) { } } -func cacheISO(cfg *config.ClusterConfig, driverName string) { - if !driver.BareMetal(driverName) && !driver.IsKIC(driverName) { - if err := cluster.CacheISO(*cfg); err != nil { - exit.WithError("Failed to cache ISO", err) - } - } -} - func displayVersion(version string) { prefix := "" - if viper.GetString(config.MachineProfile) != constants.DefaultMachineName { - prefix = fmt.Sprintf("[%s] ", viper.GetString(config.MachineProfile)) + if viper.GetString(config.ProfileName) != constants.DefaultClusterName { + prefix = fmt.Sprintf("[%s] ", viper.GetString(config.ProfileName)) } versionState := out.Happy @@ -465,12 +465,6 @@ func selectDriver(existing *config.ClusterConfig) registry.DriverState { // Technically unrelated, but important to perform before detection driver.SetLibvirtURI(viper.GetString(kvmQemuURI)) - if viper.GetString("vm-driver") != "" { - ds := driver.Status(viper.GetString("vm-driver")) - out.T(out.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()}) - return ds - } - // By default, the driver is whatever we used last time if existing != nil && existing.Driver != "" { ds := driver.Status(existing.Driver) @@ -478,9 +472,23 @@ func selectDriver(existing *config.ClusterConfig) registry.DriverState { return ds } + // Default to looking at the new driver parameter + if viper.GetString("driver") != "" { + ds := driver.Status(viper.GetString("driver")) + out.T(out.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()}) + return ds + } + + // Fallback to old driver parameter + if viper.GetString("vm-driver") != "" { + ds := driver.Status(viper.GetString("vm-driver")) + out.T(out.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()}) + return ds + } + pick, alts := driver.Suggest(driver.Choices()) if pick.Name == "" { - exit.WithCodeT(exit.Config, "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/") + exit.WithCodeT(exit.Config, "Unable to determine a default driver to use. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/") } if len(alts) > 1 { @@ -536,9 +544,10 @@ func validateDriver(ds registry.DriverState, existing *config.ClusterConfig) { cp, err := config.PrimaryControlPlane(*existing) if err != nil { - glog.Warningf("selectDriver PrimaryControlPlane: %v", err) + exit.WithError("Error getting primary cp", err) } - machineName := driver.MachineName(viper.GetString(config.MachineProfile), cp.Name) + + machineName := driver.MachineName(*existing, cp) h, err := api.Load(machineName) if err != nil { glog.Warningf("selectDriver api.Load: %v", err) @@ -558,7 +567,7 @@ func validateDriver(ds registry.DriverState, existing *config.ClusterConfig) { * or * - 2) Start the existing "{{.profile_name}}" cluster using: '{{.command}} start --vm-driver={{.old_driver}}' + 2) Start the existing "{{.profile_name}}" cluster using: '{{.command}} start --driver={{.old_driver}}' `, out.V{"command": minikubeCmd(), "old_driver": h.Driver.DriverName(), "profile_name": machineName}) exit.WithCodeT(exit.Config, "Exiting.") @@ -617,8 +626,8 @@ func selectImageRepository(mirrorCountry string) (bool, string, error) { // Return a minikube command containing the current profile name func minikubeCmd() string { - if viper.GetString(config.MachineProfile) != constants.DefaultMachineName { - return fmt.Sprintf("minikube -p %s", config.MachineProfile) + if viper.GetString(config.ProfileName) != constants.DefaultClusterName { + return fmt.Sprintf("minikube -p %s", config.ProfileName) } return "minikube" } @@ -634,7 +643,7 @@ func validateUser(drvName string) { useForce := viper.GetBool(force) if driver.NeedsRoot(drvName) && u.Uid != "0" && !useForce { - exit.WithCodeT(exit.Permissions, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.`, out.V{"driver_name": drvName}) + exit.WithCodeT(exit.Permissions, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.`, out.V{"driver_name": drvName}) } if driver.NeedsRoot(drvName) || u.Uid != "0" { @@ -642,13 +651,13 @@ func validateUser(drvName string) { } out.T(out.Stopped, `The "{{.driver_name}}" driver should not be used with root privileges.`, out.V{"driver_name": drvName}) - out.T(out.Tip, "If you are running minikube within a VM, consider using --vm-driver=none:") + out.T(out.Tip, "If you are running minikube within a VM, consider using --driver=none:") out.T(out.Documentation, " https://minikube.sigs.k8s.io/docs/reference/drivers/none/") if !useForce { os.Exit(exit.Permissions) } - _, err = config.Load(viper.GetString(config.MachineProfile)) + _, err = config.Load(viper.GetString(config.ProfileName)) if err == nil || !config.IsNotExist(err) { out.T(out.Tip, "Tip: To remove this root owned cluster, run: sudo {{.cmd}} delete", out.V{"cmd": minikubeCmd()}) } @@ -711,7 +720,7 @@ func validateFlags(cmd *cobra.Command, drvName string) { } if driver.BareMetal(drvName) { - if viper.GetString(config.MachineProfile) != constants.DefaultMachineName { + if viper.GetString(config.ProfileName) != constants.DefaultClusterName { exit.WithCodeT(exit.Config, "The '{{.name}} driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/", out.V{"name": drvName}) } @@ -799,7 +808,7 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) var kubeNodeName string if drvName != driver.None { - kubeNodeName = viper.GetString(config.MachineProfile) + kubeNodeName = "m01" } // Create the initial node, which will necessarily be a control plane @@ -812,10 +821,9 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) } cfg := config.ClusterConfig{ - Name: viper.GetString(config.MachineProfile), + Name: viper.GetString(config.ProfileName), KeepContext: viper.GetBool(keepContext), EmbedCerts: viper.GetBool(embedCerts), - MinikubeISO: viper.GetString(isoURL), Memory: pkgutil.CalculateSizeInMB(viper.GetString(memory)), CPUs: viper.GetInt(cpus), DiskSize: pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize)), @@ -836,7 +844,6 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) KVMQemuURI: viper.GetString(kvmQemuURI), KVMGPU: viper.GetBool(kvmGPU), KVMHidden: viper.GetBool(kvmHidden), - Downloader: pkgutil.DefaultDownloader{}, DisableDriverMounts: viper.GetBool(disableDriverMounts), UUID: viper.GetString(uuid), NoVTXCheck: viper.GetBool(noVTXCheck), @@ -846,7 +853,7 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) NatNicType: viper.GetString(natNicType), KubernetesConfig: config.KubernetesConfig{ KubernetesVersion: k8sVersion, - ClusterName: viper.GetString(config.MachineProfile), + ClusterName: viper.GetString(config.ProfileName), APIServerName: viper.GetString(apiServerName), APIServerNames: apiServerNames, APIServerIPs: apiServerIPs, @@ -884,7 +891,7 @@ func setDockerProxy() { } } -// autoSetDriverOptions sets the options needed for specific vm-driver automatically. +// autoSetDriverOptions sets the options needed for specific driver automatically. func autoSetDriverOptions(cmd *cobra.Command, drvName string) (err error) { err = nil hints := driver.FlagDefaults(drvName) @@ -965,7 +972,7 @@ func getKubernetesVersion(old *config.ClusterConfig) string { if nvs.LT(ovs) { nv = version.VersionPrefix + ovs.String() profileArg := "" - if old.Name != constants.DefaultMachineName { + if old.Name != constants.DefaultClusterName { profileArg = fmt.Sprintf("-p %s", old.Name) } exit.WithCodeT(exit.Config, `Error: You have selected Kubernetes v{{.new}}, but the existing cluster for your profile is running Kubernetes v{{.old}}. Non-destructive downgrades are not supported, but you can proceed by performing one of the following options: diff --git a/cmd/minikube/cmd/status.go b/cmd/minikube/cmd/status.go index b7e3005c23..012db5a980 100644 --- a/cmd/minikube/cmd/status.go +++ b/cmd/minikube/cmd/status.go @@ -100,15 +100,14 @@ var statusCmd = &cobra.Command{ } defer api.Close() - cluster := viper.GetString(config.MachineProfile) - cc, err := config.Load(cluster) + cc, err := config.Load(viper.GetString(config.ProfileName)) if err != nil { exit.WithError("getting config", err) } var st *Status for _, n := range cc.Nodes { - machineName := driver.MachineName(cluster, n.Name) + machineName := driver.MachineName(*cc, n) st, err = status(api, machineName, n.ControlPlane) if err != nil { glog.Errorf("status error: %v", err) diff --git a/cmd/minikube/cmd/stop.go b/cmd/minikube/cmd/stop.go index a1bb3e782c..e8a20feb3e 100644 --- a/cmd/minikube/cmd/stop.go +++ b/cmd/minikube/cmd/stop.go @@ -17,6 +17,7 @@ limitations under the License. package cmd import ( + "github.com/docker/machine/libmachine" "github.com/spf13/cobra" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" @@ -39,7 +40,7 @@ itself, leaving all files intact. The cluster can be started again with the "sta // runStop handles the executes the flow of "minikube stop" func runStop(cmd *cobra.Command, args []string) { - profile := viper.GetString(pkg_config.MachineProfile) + profile := viper.GetString(pkg_config.ProfileName) api, err := machine.NewAPIClient() if err != nil { exit.WithError("Error getting client", err) @@ -48,21 +49,16 @@ func runStop(cmd *cobra.Command, args []string) { cc, err := config.Load(profile) if err != nil { - exit.WithError("Error retrieving config", err) + exit.WithError("Error getting cluster config", err) } - // TODO replace this back with expo backoff for _, n := range cc.Nodes { - err := machine.StopHost(api, driver.MachineName(profile, n.Name)) - if err != nil { - exit.WithError("Unable to stop VM", err) - } - /*if err := retry.Expo(fn, 5*time.Second, 3*time.Minute, 5); err != nil { - exit.WithError("Unable to stop VM", err) - }*/ - } + nonexistent := stop(api, *cc, n) - out.T(out.Stopped, `"{{.profile_name}}" stopped.`, out.V{"profile_name": profile}) + if !nonexistent { + out.T(out.Stopped, `"{{.node_name}}" stopped.`, out.V{"node_name": n.Name}) + } + } if err := killMountProcess(); err != nil { out.T(out.WarningType, "Unable to kill mount process: {{.error}}", out.V{"error": err}) @@ -73,3 +69,20 @@ func runStop(cmd *cobra.Command, args []string) { exit.WithError("update config", err) } } + +func stop(api libmachine.API, cluster config.ClusterConfig, n config.Node) bool { + nonexistent := false + + // TODO replace this back with expo backoff + for _, n := range cluster.Nodes { + err := machine.StopHost(api, driver.MachineName(cluster, n)) + if err != nil { + exit.WithError("Unable to stop VM", err) + } + /*if err := retry.Expo(fn, 5*time.Second, 3*time.Minute, 5); err != nil { + exit.WithError("Unable to stop VM", err) + }*/ + } + + return nonexistent +} diff --git a/cmd/minikube/cmd/tunnel.go b/cmd/minikube/cmd/tunnel.go index 8fdcae40a6..6bd63abd2c 100644 --- a/cmd/minikube/cmd/tunnel.go +++ b/cmd/minikube/cmd/tunnel.go @@ -20,16 +20,23 @@ import ( "context" "os" "os/signal" + "path/filepath" + "runtime" + "strconv" "time" "github.com/golang/glog" "github.com/spf13/cobra" "github.com/spf13/viper" + + "k8s.io/minikube/pkg/drivers/kic/oci" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/service" "k8s.io/minikube/pkg/minikube/tunnel" + "k8s.io/minikube/pkg/minikube/tunnel/kic" ) var cleanup bool @@ -69,6 +76,11 @@ var tunnelCmd = &cobra.Command{ exit.WithError("error creating clientset", err) } + cfg, err := config.Load(viper.GetString(config.ProfileName)) + if err != nil { + exit.WithError("Error getting config", err) + } + ctrlC := make(chan os.Signal, 1) signal.Notify(ctrlC, os.Interrupt) ctx, cancel := context.WithCancel(context.Background()) @@ -77,10 +89,23 @@ var tunnelCmd = &cobra.Command{ cancel() }() - cfg, err := config.Load(viper.GetString(config.MachineProfile)) - if err != nil { - exit.WithError("Error getting config", err) + if runtime.GOOS == "darwin" && cfg.Driver == oci.Docker { + port, err := oci.HostPortBinding(oci.Docker, cfg.Name, 22) + if err != nil { + exit.WithError("error getting ssh port", err) + } + sshPort := strconv.Itoa(port) + sshKey := filepath.Join(localpath.MiniPath(), "machines", cfg.Name, "id_rsa") + + kicSSHTunnel := kic.NewSSHTunnel(ctx, sshPort, sshKey, clientset.CoreV1()) + err = kicSSHTunnel.Start() + if err != nil { + exit.WithError("error starting tunnel", err) + } + + return } + done, err := manager.StartTunnel(ctx, cfg.Name, api, config.DefaultLoader, clientset.CoreV1()) if err != nil { exit.WithError("error starting tunnel", err) diff --git a/cmd/minikube/cmd/unpause.go b/cmd/minikube/cmd/unpause.go index c62165c356..8b77f10d5d 100644 --- a/cmd/minikube/cmd/unpause.go +++ b/cmd/minikube/cmd/unpause.go @@ -27,6 +27,7 @@ import ( "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" @@ -37,7 +38,7 @@ var unpauseCmd = &cobra.Command{ Use: "unpause", Short: "unpause Kubernetes", Run: func(cmd *cobra.Command, args []string) { - cname := viper.GetString(config.MachineProfile) + cname := viper.GetString(config.ProfileName) api, err := machine.NewAPIClient() if err != nil { exit.WithError("Error getting client", err) @@ -54,39 +55,43 @@ var unpauseCmd = &cobra.Command{ os.Exit(1) } glog.Infof("config: %+v", cc) - host, err := machine.CheckIfHostExistsAndLoad(api, cname) - if err != nil { - exit.WithError("Error getting host", err) - } - r, err := machine.CommandRunner(host) - if err != nil { - exit.WithError("Failed to get command runner", err) - } - - cr, err := cruntime.New(cruntime.Config{Type: cc.KubernetesConfig.ContainerRuntime, Runner: r}) - if err != nil { - exit.WithError("Failed runtime", err) - } - - glog.Infof("namespaces: %v keys: %v", namespaces, viper.AllSettings()) - if allNamespaces { - namespaces = nil //all - } else { - if len(namespaces) == 0 { - exit.WithCodeT(exit.BadUsage, "Use -A to specify all namespaces") + for _, n := range cc.Nodes { + machineName := driver.MachineName(*cc, n) + host, err := machine.CheckIfHostExistsAndLoad(api, machineName) + if err != nil { + exit.WithError("Error getting host", err) } - } - ids, err := cluster.Unpause(cr, r, namespaces) - if err != nil { - exit.WithError("Pause", err) - } + r, err := machine.CommandRunner(host) + if err != nil { + exit.WithError("Failed to get command runner", err) + } - if namespaces == nil { - out.T(out.Pause, "Unpaused kubelet and {{.count}} containers", out.V{"count": len(ids)}) - } else { - out.T(out.Pause, "Unpaused kubelet and {{.count}} containers in: {{.namespaces}}", out.V{"count": len(ids), "namespaces": strings.Join(namespaces, ", ")}) + cr, err := cruntime.New(cruntime.Config{Type: cc.KubernetesConfig.ContainerRuntime, Runner: r}) + if err != nil { + exit.WithError("Failed runtime", err) + } + + glog.Infof("namespaces: %v keys: %v", namespaces, viper.AllSettings()) + if allNamespaces { + namespaces = nil //all + } else { + if len(namespaces) == 0 { + exit.WithCodeT(exit.BadUsage, "Use -A to specify all namespaces") + } + } + + ids, err := cluster.Unpause(cr, r, namespaces) + if err != nil { + exit.WithError("Pause", err) + } + + if namespaces == nil { + out.T(out.Pause, "Unpaused kubelet and {{.count}} containers", out.V{"count": len(ids)}) + } else { + out.T(out.Pause, "Unpaused kubelet and {{.count}} containers in: {{.namespaces}}", out.V{"count": len(ids), "namespaces": strings.Join(namespaces, ", ")}) + } } }, diff --git a/cmd/minikube/cmd/update-context.go b/cmd/minikube/cmd/update-context.go index 5a5dac761b..2532672bbc 100644 --- a/cmd/minikube/cmd/update-context.go +++ b/cmd/minikube/cmd/update-context.go @@ -39,7 +39,7 @@ var updateContextCmd = &cobra.Command{ exit.WithError("Error getting client", err) } defer api.Close() - machineName := viper.GetString(config.MachineProfile) + machineName := viper.GetString(config.ProfileName) ip, err := cluster.GetHostDriverIP(api, machineName) if err != nil { exit.WithError("Error host driver ip status", err) diff --git a/deploy/iso/minikube-iso/configs/minikube_defconfig b/deploy/iso/minikube-iso/configs/minikube_defconfig index 3652860308..381d88d2c7 100644 --- a/deploy/iso/minikube-iso/configs/minikube_defconfig +++ b/deploy/iso/minikube-iso/configs/minikube_defconfig @@ -68,3 +68,5 @@ BR2_PACKAGE_STRACE=y BR2_PACKAGE_SYSSTAT=y BR2_PACKAGE_HTOP=y BR2_PACKAGE_CONNTRACK_TOOLS=y +BR2_PACKAGE_TAR=y +BR2_PACKAGE_LZ4=y diff --git a/deploy/iso/minikube-iso/package/Config.in b/deploy/iso/minikube-iso/package/Config.in index 400af6d19b..723e2f42b0 100644 --- a/deploy/iso/minikube-iso/package/Config.in +++ b/deploy/iso/minikube-iso/package/Config.in @@ -7,8 +7,8 @@ menu "System tools" source "$BR2_EXTERNAL_MINIKUBE_PATH/package/crictl-bin/Config.in" source "$BR2_EXTERNAL_MINIKUBE_PATH/package/automount/Config.in" source "$BR2_EXTERNAL_MINIKUBE_PATH/package/docker-bin/Config.in" - source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni-bin/Config.in" - source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni-plugins-bin/Config.in" + source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni/Config.in" + source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni-plugins/Config.in" source "$BR2_EXTERNAL_MINIKUBE_PATH/package/hyperv-daemons/Config.in" source "$BR2_EXTERNAL_MINIKUBE_PATH/package/gluster/Config.in" source "$BR2_EXTERNAL_MINIKUBE_PATH/package/vbox-guest/Config.in" diff --git a/deploy/iso/minikube-iso/package/cni-bin/Config.in b/deploy/iso/minikube-iso/package/cni-bin/Config.in deleted file mode 100644 index 9a0f860c67..0000000000 --- a/deploy/iso/minikube-iso/package/cni-bin/Config.in +++ /dev/null @@ -1,4 +0,0 @@ -config BR2_PACKAGE_CNI_BIN - bool "cni-bin" - default y - depends on BR2_x86_64 diff --git a/deploy/iso/minikube-iso/package/cni-bin/cni-bin.mk b/deploy/iso/minikube-iso/package/cni-bin/cni-bin.mk deleted file mode 100644 index bbc3cbe7bf..0000000000 --- a/deploy/iso/minikube-iso/package/cni-bin/cni-bin.mk +++ /dev/null @@ -1,29 +0,0 @@ -################################################################################ -# -# cni-bin -# -################################################################################ - -CNI_BIN_VERSION = v0.6.0 -CNI_BIN_SITE = https://github.com/containernetworking/cni/releases/download/$(CNI_BIN_VERSION) -CNI_BIN_SOURCE = cni-amd64-$(CNI_BIN_VERSION).tgz - -define CNI_BIN_INSTALL_TARGET_CMDS - $(INSTALL) -D -m 0755 \ - $(@D)/noop \ - $(TARGET_DIR)/opt/cni/bin/noop - - ln -sf \ - ../../opt/cni/bin/noop \ - $(TARGET_DIR)/usr/bin/noop - - $(INSTALL) -D -m 0755 \ - $(@D)/noop \ - $(TARGET_DIR)/opt/cni/bin/cnitool - - ln -sf \ - ../../opt/cni/bin/cnitool \ - $(TARGET_DIR)/usr/bin/cnitool -endef - -$(eval $(generic-package)) diff --git a/deploy/iso/minikube-iso/package/cni-plugins-bin/Config.in b/deploy/iso/minikube-iso/package/cni-plugins-bin/Config.in deleted file mode 100644 index 4e2f7815fd..0000000000 --- a/deploy/iso/minikube-iso/package/cni-plugins-bin/Config.in +++ /dev/null @@ -1,4 +0,0 @@ -config BR2_PACKAGE_CNI_PLUGINS_BIN - bool "cni-plugins-bin" - default y - depends on BR2_x86_64 diff --git a/deploy/iso/minikube-iso/package/cni-plugins-bin/cni-plugins-bin.hash b/deploy/iso/minikube-iso/package/cni-plugins-bin/cni-plugins-bin.hash deleted file mode 100644 index b8ba3fda6f..0000000000 --- a/deploy/iso/minikube-iso/package/cni-plugins-bin/cni-plugins-bin.hash +++ /dev/null @@ -1 +0,0 @@ -sha256 f04339a21b8edf76d415e7f17b620e63b8f37a76b2f706671587ab6464411f2d cni-plugins-amd64-v0.6.0.tgz diff --git a/deploy/iso/minikube-iso/package/cni-plugins/Config.in b/deploy/iso/minikube-iso/package/cni-plugins/Config.in new file mode 100644 index 0000000000..9566518974 --- /dev/null +++ b/deploy/iso/minikube-iso/package/cni-plugins/Config.in @@ -0,0 +1,5 @@ +config BR2_PACKAGE_CNI_PLUGINS + bool "cni-plugins" + default y + depends on BR2_x86_64 + depends on BR2_PACKAGE_HOST_GO_ARCH_SUPPORTS diff --git a/deploy/iso/minikube-iso/package/cni-plugins/cni-plugins.hash b/deploy/iso/minikube-iso/package/cni-plugins/cni-plugins.hash new file mode 100644 index 0000000000..01819019cb --- /dev/null +++ b/deploy/iso/minikube-iso/package/cni-plugins/cni-plugins.hash @@ -0,0 +1,4 @@ +sha256 f04339a21b8edf76d415e7f17b620e63b8f37a76b2f706671587ab6464411f2d cni-plugins-amd64-v0.6.0.tgz +sha256 8589670f7f9b211a351dfcd211d4fe0b961d77283a7415443dc188f3dbf05668 v0.6.0.tar.gz +sha256 92c7599918be0a720ac020f137cdeac746dfa03da6b26e08a37132c5728c091f v0.7.5.tar.gz +sha256 9d1526ed965ac6562fd95a931ab2346b3c5efd58c2f569038ba3c530f7e66472 v0.8.5.tar.gz diff --git a/deploy/iso/minikube-iso/package/cni-plugins-bin/cni-plugins-bin.mk b/deploy/iso/minikube-iso/package/cni-plugins/cni-plugins.mk similarity index 59% rename from deploy/iso/minikube-iso/package/cni-plugins-bin/cni-plugins-bin.mk rename to deploy/iso/minikube-iso/package/cni-plugins/cni-plugins.mk index 44239195b8..c670efeaa6 100644 --- a/deploy/iso/minikube-iso/package/cni-plugins-bin/cni-plugins-bin.mk +++ b/deploy/iso/minikube-iso/package/cni-plugins/cni-plugins.mk @@ -1,16 +1,39 @@ ################################################################################ # -# cni-plugins-bin +# cni-plugins # ################################################################################ -CNI_PLUGINS_BIN_VERSION = v0.6.0 -CNI_PLUGINS_BIN_SITE = https://github.com/containernetworking/plugins/releases/download/$(CNI_PLUGINS_BIN_VERSION) -CNI_PLUGINS_BIN_SOURCE = cni-plugins-amd64-$(CNI_PLUGINS_BIN_VERSION).tgz +CNI_PLUGINS_VERSION = v0.8.5 +CNI_PLUGINS_SITE = https://github.com/containernetworking/plugins/archive +CNI_PLUGINS_SOURCE = $(CNI_PLUGINS_VERSION).tar.gz +CNI_PLUGINS_LICENSE = Apache-2.0 +CNI_PLUGINS_LICENSE_FILES = LICENSE -define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS +CNI_PLUGINS_DEPENDENCIES = host-go + +CNI_PLUGINS_MAKE_ENV = \ + CGO_ENABLED=0 \ + GO111MODULE=off + +CNI_PLUGINS_BUILDFLAGS = -a -ldflags '-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=$(CNI_PLUGINS_VERSION)' + + +define CNI_PLUGINS_BUILD_CMDS + (cd $(@D); $(CNI_PLUGINS_MAKE_ENV) ./build_linux.sh $(CNI_PLUGINS_BUILDFLAGS)) +endef + +define CNI_PLUGINS_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 \ - $(@D)/bridge \ + $(@D)/bin/bandwidth \ + $(TARGET_DIR)/opt/cni/bin/bandwidth + + ln -sf \ + ../../opt/cni/bin/bandwidth \ + $(TARGET_DIR)/usr/bin/bandwidth + + $(INSTALL) -D -m 0755 \ + $(@D)/bin/bridge \ $(TARGET_DIR)/opt/cni/bin/bridge ln -sf \ @@ -18,7 +41,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/bridge $(INSTALL) -D -m 0755 \ - $(@D)/vlan \ + $(@D)/bin/vlan \ $(TARGET_DIR)/opt/cni/bin/vlan ln -sf \ @@ -26,7 +49,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/vlan $(INSTALL) -D -m 0755 \ - $(@D)/tuning \ + $(@D)/bin/tuning \ $(TARGET_DIR)/opt/cni/bin/tuning ln -sf \ @@ -34,15 +57,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/tuning $(INSTALL) -D -m 0755 \ - $(@D)/sample \ - $(TARGET_DIR)/opt/cni/bin/sample - - ln -sf \ - ../../opt/cni/bin/sample \ - $(TARGET_DIR)/usr/bin/sample - - $(INSTALL) -D -m 0755 \ - $(@D)/ptp \ + $(@D)/bin/ptp \ $(TARGET_DIR)/opt/cni/bin/ptp ln -sf \ @@ -50,7 +65,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/ptp $(INSTALL) -D -m 0755 \ - $(@D)/portmap \ + $(@D)/bin/portmap \ $(TARGET_DIR)/opt/cni/bin/portmap ln -sf \ @@ -58,7 +73,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/portmap $(INSTALL) -D -m 0755 \ - $(@D)/macvlan \ + $(@D)/bin/macvlan \ $(TARGET_DIR)/opt/cni/bin/macvlan ln -sf \ @@ -66,7 +81,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/macvlan $(INSTALL) -D -m 0755 \ - $(@D)/loopback \ + $(@D)/bin/loopback \ $(TARGET_DIR)/opt/cni/bin/loopback ln -sf \ @@ -74,7 +89,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/loopback $(INSTALL) -D -m 0755 \ - $(@D)/ipvlan \ + $(@D)/bin/ipvlan \ $(TARGET_DIR)/opt/cni/bin/ipvlan ln -sf \ @@ -82,7 +97,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/ipvlan $(INSTALL) -D -m 0755 \ - $(@D)/host-local \ + $(@D)/bin/host-local \ $(TARGET_DIR)/opt/cni/bin/host-local ln -sf \ @@ -90,7 +105,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/host-local $(INSTALL) -D -m 0755 \ - $(@D)/flannel \ + $(@D)/bin/flannel \ $(TARGET_DIR)/opt/cni/bin/flannel ln -sf \ @@ -99,12 +114,20 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 \ - $(@D)/dhcp \ + $(@D)/bin/dhcp \ $(TARGET_DIR)/opt/cni/bin/dhcp ln -sf \ ../../opt/cni/bin/dhcp \ $(TARGET_DIR)/usr/bin/dhcp + + $(INSTALL) -D -m 0755 \ + $(@D)/bin/firewall \ + $(TARGET_DIR)/opt/cni/bin/firewall + + ln -sf \ + ../../opt/cni/bin/firewall \ + $(TARGET_DIR)/usr/bin/firewall endef $(eval $(generic-package)) diff --git a/deploy/iso/minikube-iso/package/cni/Config.in b/deploy/iso/minikube-iso/package/cni/Config.in new file mode 100644 index 0000000000..ca60da49fc --- /dev/null +++ b/deploy/iso/minikube-iso/package/cni/Config.in @@ -0,0 +1,5 @@ +config BR2_PACKAGE_CNI + bool "cni" + default y + depends on BR2_x86_64 + depends on BR2_PACKAGE_HOST_GO_ARCH_SUPPORTS diff --git a/deploy/iso/minikube-iso/package/cni-bin/cni-bin.hash b/deploy/iso/minikube-iso/package/cni/cni.hash similarity index 50% rename from deploy/iso/minikube-iso/package/cni-bin/cni-bin.hash rename to deploy/iso/minikube-iso/package/cni/cni.hash index ba8d154f6d..f8b1c8278f 100644 --- a/deploy/iso/minikube-iso/package/cni-bin/cni-bin.hash +++ b/deploy/iso/minikube-iso/package/cni/cni.hash @@ -1,3 +1,6 @@ sha256 b1ae09833a238c51161918a8849031efdb46cf0068ea5b752e362d9836e2af7d cni-v0.3.0.tgz sha256 84c9a0a41b59211d560bef14bf3f53bb370156f9ac7762270b3848fed96e1be8 cni-v0.4.0.tgz sha256 a7f84a742c8f3a95843b3cc636444742554a4853835649ec371a07c841daebab cni-amd64-v0.6.0.tgz +sha256 802f4a002b4eb774624a9dc1c859d3c9926eb2d862e66a673fc99cfc8bcd7494 v0.6.0.tar.gz +sha256 78d57477d6b0ab9dc4d75ce9f275302d2f379206b5326503e57d9c08b76484c1 v0.7.0.tar.gz +sha256 4517eabfd65aea2012dc48d057bf889a0a41ed9837387d95cd1e36c0dbddcfd4 v0.7.1.tar.gz diff --git a/deploy/iso/minikube-iso/package/cni/cni.mk b/deploy/iso/minikube-iso/package/cni/cni.mk new file mode 100644 index 0000000000..14599e0876 --- /dev/null +++ b/deploy/iso/minikube-iso/package/cni/cni.mk @@ -0,0 +1,44 @@ +################################################################################ +# +# cni +# +################################################################################ + +CNI_VERSION = v0.7.1 +CNI_SITE = https://github.com/containernetworking/cni/archive +CNI_SOURCE = $(CNI_VERSION).tar.gz +CNI_LICENSE = Apache-2.0 +CNI_LICENSE_FILES = LICENSE + +CNI_DEPENDENCIES = host-go + +CNI_GOPATH = $(@D)/_output +CNI_MAKE_ENV = \ + CGO_ENABLED=0 \ + GO111MODULE=off \ + GOPATH="$(CNI_GOPATH)" \ + GOBIN="$(CNI_GOPATH)/bin" \ + PATH=$(CNI_GOPATH)/bin:$(BR_PATH) + +CNI_BUILDFLAGS = -a --ldflags '-extldflags \"-static\"' + +define CNI_CONFIGURE_CMDS + mkdir -p $(CNI_GOPATH)/src/github.com/containernetworking + ln -sf $(@D) $(CNI_GOPATH)/src/github.com/containernetworking/cni +endef + +define CNI_BUILD_CMDS + (cd $(@D); $(CNI_MAKE_ENV) go build -o bin/cnitool $(CNI_BUILDFLAGS) ./cnitool) +endef + +define CNI_INSTALL_TARGET_CMDS + $(INSTALL) -D -m 0755 \ + $(@D)/bin/cnitool \ + $(TARGET_DIR)/opt/cni/bin/cnitool + + ln -sf \ + ../../opt/cni/bin/cnitool \ + $(TARGET_DIR)/usr/bin/cnitool +endef + +$(eval $(generic-package)) diff --git a/deploy/iso/minikube-iso/package/containerd-bin/config.toml b/deploy/iso/minikube-iso/package/containerd-bin/config.toml index 5d014ca5fc..883099141c 100644 --- a/deploy/iso/minikube-iso/package/containerd-bin/config.toml +++ b/deploy/iso/minikube-iso/package/containerd-bin/config.toml @@ -31,7 +31,7 @@ oom_score = 0 enable_selinux = false sandbox_image = "k8s.gcr.io/pause:3.1" stats_collect_period = 10 - systemd_cgroup = false + systemd_cgroup = true enable_tls_streaming = false max_container_log_line_size = 16384 [plugins.cri.containerd] diff --git a/deploy/iso/minikube-iso/package/crio-bin/crio.conf b/deploy/iso/minikube-iso/package/crio-bin/crio.conf index d473a85d8c..36dc1725ea 100644 --- a/deploy/iso/minikube-iso/package/crio-bin/crio.conf +++ b/deploy/iso/minikube-iso/package/crio-bin/crio.conf @@ -120,7 +120,7 @@ seccomp_profile = "" apparmor_profile = "crio-default-1.16.1" # Cgroup management implementation used for the runtime. -cgroup_manager = "cgroupfs" +cgroup_manager = "systemd" # List of default capabilities for containers. If it is empty or commented out, # only the capabilities defined in the containers json file by the user/kube diff --git a/deploy/iso/minikube-iso/package/docker-bin/daemon.json b/deploy/iso/minikube-iso/package/docker-bin/daemon.json new file mode 100644 index 0000000000..46c2107f11 --- /dev/null +++ b/deploy/iso/minikube-iso/package/docker-bin/daemon.json @@ -0,0 +1,10 @@ +{ + "exec-opts": [ + "native.cgroupdriver=systemd" + ], + "log-driver": "json-file", + "log-opts": { + "max-size": "100m" + }, + "storage-driver": "overlay2" +} diff --git a/deploy/iso/minikube-iso/package/docker-bin/docker-bin.mk b/deploy/iso/minikube-iso/package/docker-bin/docker-bin.mk index 2cafaadc6b..81978dbfd9 100644 --- a/deploy/iso/minikube-iso/package/docker-bin/docker-bin.mk +++ b/deploy/iso/minikube-iso/package/docker-bin/docker-bin.mk @@ -34,6 +34,12 @@ define DOCKER_BIN_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 \ $(@D)/docker-proxy \ $(TARGET_DIR)/bin/docker-proxy + + # https://kubernetes.io/docs/setup/production-environment/container-runtimes/#docker + + $(INSTALL) -Dm644 \ + $(DOCKER_BIN_PKGDIR)/daemon.json \ + $(TARGET_DIR)/etc/docker/daemon.json endef define DOCKER_BIN_INSTALL_INIT_SYSTEMD diff --git a/deploy/iso/minikube-iso/package/falco-probe/falco-probe.hash b/deploy/iso/minikube-iso/package/falco-probe/falco-probe.hash index efe14c5233..a8afdf53cc 100644 --- a/deploy/iso/minikube-iso/package/falco-probe/falco-probe.hash +++ b/deploy/iso/minikube-iso/package/falco-probe/falco-probe.hash @@ -1,4 +1,5 @@ # falco sha256 87c60273c35d544256e471b403497be33f24df662673338236ec92ba3fc1f8b7 0.19.0.tar.gz +sha256 b873e3590e56ead740ed905108221f98da6100da3c5b7acf2355ea1cf628d931 0.20.0.tar.gz # sysdig sha256 6e477ac5fe9d3110b870bd4495f01541373a008c375a1934a2d1c46798b6bad6 146a431edf95829ac11bfd9c85ba3ef08789bffe.tar.gz diff --git a/deploy/iso/minikube-iso/package/falco-probe/falco-probe.mk b/deploy/iso/minikube-iso/package/falco-probe/falco-probe.mk index b96bbec29b..0e5986f1fc 100644 --- a/deploy/iso/minikube-iso/package/falco-probe/falco-probe.mk +++ b/deploy/iso/minikube-iso/package/falco-probe/falco-probe.mk @@ -4,7 +4,7 @@ # ######################################################################## -FALCO_PROBE_VERSION = 0.19.0 +FALCO_PROBE_VERSION = 0.20.0 FALCO_PROBE_SITE = https://github.com/falcosecurity/falco/archive FALCO_PROBE_SOURCE = $(FALCO_PROBE_VERSION).tar.gz FALCO_PROBE_DEPENDENCIES += ncurses libyaml @@ -22,7 +22,6 @@ endef FALCO_PROBE_POST_EXTRACT_HOOKS += FALCO_PROBE_SYSDIG_SRC FALCO_PROBE_CONF_OPTS = -DFALCO_VERSION=$(FALCO_PROBE_VERSION) -FALCO_PROBE_CONF_OPTS += -DSYSDIG_VERSION=$(FALCO_PROBE_SYSDIG_VERSION) FALCO_PROBE_CONF_OPTS += -DUSE_BUNDLED_DEPS=ON FALCO_PROBE_MAKE_OPTS = driver KERNELDIR=$(LINUX_DIR) diff --git a/go.mod b/go.mod index 91462732ff..6503b4285f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module k8s.io/minikube go 1.13 require ( + cloud.google.com/go v0.45.1 github.com/Parallels/docker-machine-parallels v1.3.0 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/blang/semver v3.5.0+incompatible @@ -11,6 +12,7 @@ require ( github.com/cheggaaa/pb/v3 v3.0.1 github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect + github.com/docker/cli v0.0.0-20200303162255-7d407207c304 // indirect github.com/docker/docker v1.13.1 github.com/docker/go-units v0.4.0 github.com/docker/machine v0.7.1-0.20190718054102-a555e4f7a8f5 // version is 0.7.1 to pin to a555e4f7a8f5 @@ -23,15 +25,12 @@ require ( github.com/google/go-cmp v0.3.0 github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2 github.com/googleapis/gnostic v0.3.0 // indirect - github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce // indirect github.com/hashicorp/go-getter v1.4.0 - github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 // indirect github.com/hashicorp/go-retryablehttp v0.5.4 github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8 github.com/imdario/mergo v0.3.8 // indirect github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 // indirect - github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345 github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d // indirect @@ -65,17 +64,20 @@ require ( github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be 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-20191206172530-e9b2fee46413 + golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 + golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e golang.org/x/sys v0.0.0-20191010194322-b09406accb47 golang.org/x/text v0.3.2 + google.golang.org/api v0.9.0 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect + gotest.tools/v3 v3.0.2 // indirect k8s.io/api v0.17.3 k8s.io/apimachinery v0.17.3 k8s.io/client-go v0.17.3 k8s.io/kubectl v0.0.0 k8s.io/kubernetes v1.17.3 - k8s.io/utils v0.0.0-20200122174043-1e243dd1a584 // indirect + k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab // indirect sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.0+incompatible ) diff --git a/go.sum b/go.sum index 8d6e6da84b..43d58cc925 100644 --- a/go.sum +++ b/go.sum @@ -144,6 +144,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200303162255-7d407207c304 h1:A7SYzidcyuQ/yS4wezWGYeUioUFJQk8HYWY9aMYTF4I= +github.com/docker/cli v0.0.0-20200303162255-7d407207c304/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 h1:Cvj7S8I4Xpx78KAl6TwTmMHuHlZ/0SM60NUneGJQ7IE= @@ -346,12 +348,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 h1:VIq8E7fMiC4h3agg0ya56L0jHn7QisZZcWZXVKJb9jQ= -github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE= github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= @@ -386,8 +384,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 h1:XboatR7lasl05yel5hNXF7kQBw2oFUGdMztcgisfhNU= github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6/go.mod h1:RmeVYf9XrPRbRc3XIx0gLYA8qOFvNoPOfaEZduRlEp4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b h1:3TknJxYSK1eDe21QorC3C2Yz8jylk6vlJG9YABnFzkU= -github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b/go.mod h1:I3WsAhNNoG7a/d8HMlYUywJJlfOs/+/83NEUjuDp4lc= github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -735,6 +731,8 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -780,6 +778,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= @@ -864,6 +864,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -944,6 +945,8 @@ gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= +gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -996,8 +999,8 @@ k8s.io/sample-apiserver v0.17.3/go.mod h1:cn/rvFIttGNqy1v88B5ZlDAbyyqDOoF7JHSwPi k8s.io/system-validators v1.0.4/go.mod h1:HgSgTg4NAGNoYYjKsUyk52gdNi2PVDswQ9Iyn66R7NI= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200122174043-1e243dd1a584 h1:3tT5mBZNurtd5BoYrPBII3Sa8n7T2w405qdTQvr3vmY= -k8s.io/utils v0.0.0-20200122174043-1e243dd1a584/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab h1:I3f2hcBrepGRXI1z4sukzAb8w1R4eqbsHrAsx06LGYM= +k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= diff --git a/hack/conformance_tests.sh b/hack/conformance_tests.sh index cff11af0a3..3de828e59e 100755 --- a/hack/conformance_tests.sh +++ b/hack/conformance_tests.sh @@ -21,7 +21,7 @@ # conformance_tests.sh # # Example: -# conformance_tests.sh ./out/minikube --vm-driver=hyperkit +# conformance_tests.sh ./out/minikube --driver=hyperkit set -ex -o pipefail readonly PROFILE_NAME="k8sconformance" diff --git a/hack/images/kicbase.Dockerfile b/hack/images/kicbase.Dockerfile index 631f67b5b6..baadf88df3 100644 --- a/hack/images/kicbase.Dockerfile +++ b/hack/images/kicbase.Dockerfile @@ -52,13 +52,3 @@ RUN apt-get clean -y && rm -rf \ /usr/share/man/* \ /usr/share/local/* \ RUN echo "kic! Build: ${COMMIT_SHA} Time :$(date)" > "/kic.txt" - - -FROM busybox -ARG KUBERNETES_VERSION -COPY out/preloaded-images-k8s-$KUBERNETES_VERSION.tar /preloaded-images.tar -RUN tar xvf /preloaded-images.tar -C / - -FROM base -COPY --from=1 /var/lib/docker /var/lib/docker -COPY --from=1 /var/lib/minikube/binaries /var/lib/minikube/binaries diff --git a/hack/jenkins/common.sh b/hack/jenkins/common.sh index db91e1af6f..d9cfca7f5b 100755 --- a/hack/jenkins/common.sh +++ b/hack/jenkins/common.sh @@ -19,7 +19,7 @@ # The script expects the following env variables: # OS_ARCH: The operating system and the architecture separated by a hyphen '-' (e.g. darwin-amd64, linux-amd64, windows-amd64) -# VM_DRIVER: the vm-driver to use for the test +# VM_DRIVER: the driver to use for the test # EXTRA_START_ARGS: additional flags to pass into minikube start # EXTRA_ARGS: additional flags to pass into minikube # JOB_NAME: the name of the logfile and check name to update on github @@ -31,9 +31,9 @@ export KUBECONFIG="${TEST_HOME}/kubeconfig" export PATH=$PATH:"/usr/local/bin/:/usr/local/go/bin/:$GOPATH/bin" # installing golang so we could do go get for gopogh -sudo ./installers/check_install_golang.sh "1.13.4" "/usr/local" || true +sudo ./installers/check_install_golang.sh "1.13.6" "/usr/local" || true -docker rm -f $(docker ps -aq) >/dev/null 2>&1 || true +docker rm -f -v $(docker ps -aq) >/dev/null 2>&1 || true docker volume prune -f || true docker system df || true @@ -285,7 +285,7 @@ if test -f "${TEST_OUT}"; then fi touch "${TEST_OUT}" ${SUDO_PREFIX}${E2E_BIN} \ - -minikube-start-args="--vm-driver=${VM_DRIVER} ${EXTRA_START_ARGS}" \ + -minikube-start-args="--driver=${VM_DRIVER} ${EXTRA_START_ARGS}" \ -expected-default-driver="${EXPECTED_DEFAULT_DRIVER}" \ -test.timeout=70m -test.v \ ${EXTRA_TEST_ARGS} \ diff --git a/hack/jenkins/cron/cleanup_and_reboot_Darwin.sh b/hack/jenkins/cron/cleanup_and_reboot_Darwin.sh index 993d6c82f6..75c7dfedb4 100755 --- a/hack/jenkins/cron/cleanup_and_reboot_Darwin.sh +++ b/hack/jenkins/cron/cleanup_and_reboot_Darwin.sh @@ -41,6 +41,13 @@ logger "cleanup_and_reboot is happening!" # kill jenkins to avoid an incoming request killall java +# clean docker left overs +docker rm -f -v $(docker ps -aq) >/dev/null 2>&1 || true +docker volume prune -f || true +docker volume ls || true +docker system df || true + + # macOS specific cleanup sudo rm /var/db/dhcpd_leases || echo "could not clear dhcpd leases" sudo softwareupdate -i -a -R diff --git a/hack/jenkins/cron/cleanup_and_reboot_Linux.sh b/hack/jenkins/cron/cleanup_and_reboot_Linux.sh index b2e067c58e..e03e6cd06b 100755 --- a/hack/jenkins/cron/cleanup_and_reboot_Linux.sh +++ b/hack/jenkins/cron/cleanup_and_reboot_Linux.sh @@ -36,6 +36,12 @@ logger "cleanup_and_reboot is happening!" # kill jenkins to avoid an incoming request killall java +# clean docker left overs +docker rm -f -v $(docker ps -aq) >/dev/null 2>&1 || true +docker volume prune -f || true +docker volume ls || true +docker system df || true + # Linux-specific cleanup # disable localkube, kubelet diff --git a/hack/jenkins/minikube_set_pending.sh b/hack/jenkins/minikube_set_pending.sh index c26324635a..1d91deaa31 100755 --- a/hack/jenkins/minikube_set_pending.sh +++ b/hack/jenkins/minikube_set_pending.sh @@ -41,6 +41,7 @@ jobs=( 'KVM_Linux' 'none_Linux' 'Docker_Linux' + 'Docker_macOS' 'Podman_Linux' ) diff --git a/hack/jenkins/osx_integration_tests_docker.sh b/hack/jenkins/osx_integration_tests_docker.sh new file mode 100755 index 0000000000..c2865d83ff --- /dev/null +++ b/hack/jenkins/osx_integration_tests_docker.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Copyright 2016 The Kubernetes Authors All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# This script runs the integration tests on an OSX machine for the Hyperkit Driver + +# The script expects the following env variables: +# MINIKUBE_LOCATION: GIT_COMMIT from upstream build. +# COMMIT: Actual commit ID from upstream build +# EXTRA_BUILD_ARGS (optional): Extra args to be passed into the minikube integrations tests +# access_token: The Github API access token. Injected by the Jenkins credential provider. + + +set -e + +OS_ARCH="darwin-amd64" +VM_DRIVER="docker" +JOB_NAME="Docker_macOS" +EXTRA_START_ARGS="" +EXPECTED_DEFAULT_DRIVER="hyperkit" + + +# restart docker on mac for a fresh test +osascript -e 'quit app "Docker"'; open -a Docker ; while [ -z "$(docker info 2> /dev/null )" ]; do printf "."; sleep 1; done; echo "" || true + +mkdir -p cron && gsutil -qm rsync "gs://minikube-builds/${MINIKUBE_LOCATION}/cron" cron || echo "FAILED TO GET CRON FILES" +install cron/cleanup_and_reboot_Darwin.sh $HOME/cleanup_and_reboot.sh || echo "FAILED TO INSTALL CLEANUP" +echo "*/30 * * * * $HOME/cleanup_and_reboot.sh" | crontab +crontab -l + +source common.sh diff --git a/hack/jenkins/windows_integration_test_hyperv.ps1 b/hack/jenkins/windows_integration_test_hyperv.ps1 index 4c8835d0cf..f1c4db8b9d 100644 --- a/hack/jenkins/windows_integration_test_hyperv.ps1 +++ b/hack/jenkins/windows_integration_test_hyperv.ps1 @@ -19,7 +19,7 @@ gsutil.cmd -m cp -r gs://minikube-builds/$env:MINIKUBE_LOCATION/testdata . ./out/minikube-windows-amd64.exe delete -out/e2e-windows-amd64.exe --expected-default-driver=hyperv -minikube-start-args="--vm-driver=hyperv --hyperv-virtual-switch=primary-virtual-switch" -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=65m +out/e2e-windows-amd64.exe --expected-default-driver=hyperv -minikube-start-args="--driver=hyperv --hyperv-virtual-switch=primary-virtual-switch" -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=65m $env:result=$lastexitcode # If the last exit code was 0->success, x>0->error If($env:result -eq 0){$env:status="success"} diff --git a/hack/jenkins/windows_integration_test_virtualbox.ps1 b/hack/jenkins/windows_integration_test_virtualbox.ps1 index 5cc4e157b1..6d9c7f318b 100644 --- a/hack/jenkins/windows_integration_test_virtualbox.ps1 +++ b/hack/jenkins/windows_integration_test_virtualbox.ps1 @@ -19,7 +19,7 @@ gsutil.cmd -m cp -r gs://minikube-builds/$env:MINIKUBE_LOCATION/testdata . ./out/minikube-windows-amd64.exe delete -out/e2e-windows-amd64.exe -minikube-start-args="--vm-driver=virtualbox" -expected-default-driver=hyperv -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=30m +out/e2e-windows-amd64.exe -minikube-start-args="--driver=virtualbox" -expected-default-driver=hyperv -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=30m $env:result=$lastexitcode # If the last exit code was 0->success, x>0->error If($env:result -eq 0){$env:status="success"} diff --git a/hack/preload-images/preload_images.go b/hack/preload-images/preload_images.go index 82fdba5b41..b41de29548 100644 --- a/hack/preload-images/preload_images.go +++ b/hack/preload-images/preload_images.go @@ -25,6 +25,14 @@ import ( "strings" "github.com/pkg/errors" + "k8s.io/minikube/pkg/drivers/kic" + "k8s.io/minikube/pkg/drivers/kic/oci" + "k8s.io/minikube/pkg/minikube/bootstrapper/bsutil" + "k8s.io/minikube/pkg/minikube/bootstrapper/images" + "k8s.io/minikube/pkg/minikube/command" + "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" + "k8s.io/minikube/pkg/minikube/localpath" ) const ( @@ -33,17 +41,28 @@ const ( ) var ( - kubernetesVersion = "" - tarballFilename = "" + kubernetesVersion = "" + tarballFilename = "" + dockerStorageDriver = "" + preloadedTarballVersion = "" + containerRuntime = "" ) func init() { flag.StringVar(&kubernetesVersion, "kubernetes-version", "", "desired kubernetes version, for example `v1.17.2`") + flag.StringVar(&dockerStorageDriver, "docker-storage-driver", "overlay2", "docker storage driver backend") + flag.StringVar(&preloadedTarballVersion, "preloaded-tarball-version", "", "preloaded tarball version") + flag.StringVar(&containerRuntime, "container-runtime", "docker", "container runtime") + flag.Parse() - tarballFilename = fmt.Sprintf("preloaded-images-k8s-%s.tar", kubernetesVersion) + tarballFilename = fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-%s.tar.lz4", preloadedTarballVersion, kubernetesVersion, containerRuntime, dockerStorageDriver) } func main() { + if err := verifyDockerStorage(); err != nil { + fmt.Println(err) + os.Exit(1) + } if err := executePreloadImages(); err != nil { fmt.Println(err) os.Exit(1) @@ -56,42 +75,83 @@ func executePreloadImages() error { fmt.Println(err) } }() - if err := startMinikube(); err != nil { + + driver := kic.NewDriver(kic.Config{ + KubernetesVersion: kubernetesVersion, + ContainerRuntime: driver.Docker, + OCIBinary: oci.Docker, + MachineName: profile, + ImageDigest: kic.BaseImage, + StorePath: localpath.MiniPath(), + CPU: 2, + Memory: 4000, + APIServerPort: 8080, + }) + + baseDir := filepath.Dir(driver.GetSSHKeyPath()) + defer os.Remove(baseDir) + + if err := os.MkdirAll(baseDir, 0755); err != nil { return err } + if err := driver.Create(); err != nil { + return errors.Wrap(err, "creating kic driver") + } + + // Now, get images to pull + imgs, err := images.Kubeadm("", kubernetesVersion) + if err != nil { + return errors.Wrap(err, "kubeadm images") + } + + for _, img := range append(imgs, kic.OverlayImage) { + cmd := exec.Command("docker", "exec", profile, "docker", "pull", img) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return errors.Wrapf(err, "downloading %s", img) + } + } + + // Transfer in k8s binaries + kcfg := config.KubernetesConfig{ + KubernetesVersion: kubernetesVersion, + } + runner := command.NewKICRunner(profile, driver.OCIBinary) + if err := bsutil.TransferBinaries(kcfg, runner); err != nil { + return errors.Wrap(err, "transferring k8s binaries") + } + // Create image tarball if err := createImageTarball(); err != nil { return err } return copyTarballToHost() } -func startMinikube() error { - cmd := exec.Command(minikubePath, "start", "-p", profile, "--memory", "4000", "--kubernetes-version", kubernetesVersion, "--wait=false") - cmd.Stdout = os.Stdout - return cmd.Run() -} - func createImageTarball() error { - cmd := exec.Command(minikubePath, "ssh", "-p", profile, "--", "sudo", "tar", "cvf", tarballFilename, "/var/lib/docker", "/var/lib/minikube/binaries") + dirs := []string{ + fmt.Sprintf("./lib/docker/%s", dockerStorageDriver), + "./lib/docker/image", + "./lib/minikube/binaries", + } + args := []string{"exec", profile, "sudo", "tar", "-I", "lz4", "-C", "/var", "-cvf", tarballFilename} + args = append(args, dirs...) + cmd := exec.Command("docker", args...) cmd.Stdout = os.Stdout - return cmd.Run() + if err := cmd.Run(); err != nil { + return errors.Wrap(err, "creating image tarball") + } + return nil } func copyTarballToHost() error { - sshKey, err := runCmd([]string{minikubePath, "ssh-key", "-p", profile}) - if err != nil { - return errors.Wrap(err, "getting ssh-key") - } - - ip, err := runCmd([]string{minikubePath, "ip", "-p", profile}) - if err != nil { - return errors.Wrap(err, "getting ip") - } - dest := filepath.Join("out/", tarballFilename) - args := []string{"scp", "-o", "StrictHostKeyChecking=no", "-i", sshKey, fmt.Sprintf("docker@%s:/home/docker/%s", ip, tarballFilename), dest} - _, err = runCmd(args) - return err + cmd := exec.Command("docker", "cp", fmt.Sprintf("%s:/%s", profile, tarballFilename), dest) + cmd.Stdout = os.Stdout + if err := cmd.Run(); err != nil { + return errors.Wrap(err, "copying tarball to host") + } + return nil } func deleteMinikube() error { @@ -100,8 +160,15 @@ func deleteMinikube() error { return cmd.Run() } -func runCmd(command []string) (string, error) { - cmd := exec.Command(command[0], command[1:]...) +func verifyDockerStorage() error { + cmd := exec.Command("docker", "info", "-f", "{{.Info.Driver}}") output, err := cmd.Output() - return strings.Trim(string(output), "\n "), err + if err != nil { + return err + } + driver := strings.Trim(string(output), " \n") + if driver != dockerStorageDriver { + return fmt.Errorf("docker storage driver %s does not match requested %s", driver, dockerStorageDriver) + } + return nil } diff --git a/pkg/addons/addons.go b/pkg/addons/addons.go index e1ca836c37..c62c857bbe 100644 --- a/pkg/addons/addons.go +++ b/pkg/addons/addons.go @@ -30,6 +30,7 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/out" @@ -118,6 +119,9 @@ func enableOrDisableAddon(name, val, profile string) error { if alreadySet { glog.Warningf("addon %s should already be in state %v", name, val) + if !enable { + return nil + } } if name == "istio" && enable { @@ -243,7 +247,16 @@ func enableOrDisableStorageClasses(name, val, profile string) error { } defer api.Close() - if !machine.IsHostRunning(api, profile) { + cc, err := config.Load(profile) + if err != nil { + return errors.Wrap(err, "getting cluster") + } + + cp, err := config.PrimaryControlPlane(*cc) + if err != nil { + return errors.Wrap(err, "getting control plane") + } + if !machine.IsHostRunning(api, driver.MachineName(*cc, cp)) { glog.Warningf("%q is not running, writing %s=%v to disk and skipping enablement", profile, name, val) return enableOrDisableAddon(name, val, profile) } diff --git a/pkg/drivers/kic/kic.go b/pkg/drivers/kic/kic.go index 0ecb6a2ade..f33bda1f3d 100644 --- a/pkg/drivers/kic/kic.go +++ b/pkg/drivers/kic/kic.go @@ -17,11 +17,13 @@ limitations under the License. package kic import ( + "context" "fmt" "net" "os/exec" "strconv" "strings" + "time" "github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/log" @@ -34,6 +36,7 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" ) // Driver represents a kic driver https://minikube.sigs.k8s.io/docs/reference/drivers/docker @@ -66,6 +69,7 @@ func (d *Driver) Create() error { Name: d.NodeConfig.MachineName, Image: d.NodeConfig.ImageDigest, ClusterLabel: oci.ProfileLabelKey + "=" + d.MachineName, + NodeLabel: oci.NodeLabelKey + "=" + d.NodeConfig.MachineName, CPUs: strconv.Itoa(d.NodeConfig.CPU), Memory: strconv.Itoa(d.NodeConfig.Memory) + "mb", Envs: d.NodeConfig.Envs, @@ -88,14 +92,23 @@ func (d *Driver) Create() error { ContainerPort: constants.DockerDaemonPort, }, ) - err := oci.CreateContainerNode(params) - if err != nil { + if err := oci.CreateContainerNode(params); err != nil { return errors.Wrap(err, "create kic node") } if err := d.prepareSSH(); err != nil { return errors.Wrap(err, "prepare kic ssh") } + + t := time.Now() + glog.Infof("Starting extracting preloaded images to volume") + // Extract preloaded images to container + if err := oci.ExtractTarballToVolume(download.TarballPath(d.NodeConfig.KubernetesVersion), params.Name, BaseImage); err != nil { + glog.Infof("Unable to extract preloaded tarball to volume: %v", err) + } else { + glog.Infof("Took %f seconds to extract preloaded images to volume", time.Since(t).Seconds()) + } + return nil } @@ -124,10 +137,10 @@ func (d *Driver) prepareSSH() error { // DriverName returns the name of the driver func (d *Driver) DriverName() string { - if d.NodeConfig.OCIBinary == "podman" { - return "podman" + if d.NodeConfig.OCIBinary == oci.Podman { + return oci.Podman } - return "docker" + return oci.Docker } // GetIP returns an IP or hostname that this host is available at @@ -181,11 +194,18 @@ func (d *Driver) GetURL() (string, error) { // GetState returns the state that the host is in (running, stopped, etc) func (d *Driver) GetState() (state.State, error) { if err := oci.PointToHostDockerDaemon(); err != nil { - return state.Error, errors.Wrap(err, "point host docker-daemon") + return state.Error, errors.Wrap(err, "point host docker daemon") } + // allow no more than 2 seconds for this. when this takes long this means deadline passed + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() - cmd := exec.Command(d.NodeConfig.OCIBinary, "inspect", "-f", "{{.State.Status}}", d.MachineName) + cmd := exec.CommandContext(ctx, d.NodeConfig.OCIBinary, "inspect", "-f", "{{.State.Status}}", d.MachineName) out, err := cmd.CombinedOutput() + if ctx.Err() == context.DeadlineExceeded { + glog.Errorf("GetState for %s took longer than normal. Restarting your %s daemon might fix this issue.", d.MachineName, d.OCIBinary) + return state.Error, fmt.Errorf("inspect %s timeout", d.MachineName) + } o := strings.TrimSpace(string(out)) if err != nil { return state.Error, errors.Wrapf(err, "get container %s status", d.MachineName) @@ -208,6 +228,9 @@ func (d *Driver) GetState() (state.State, error) { // Kill stops a host forcefully, including any containers that we are managing. func (d *Driver) Kill() error { + if err := oci.PointToHostDockerDaemon(); err != nil { + return errors.Wrap(err, "point host docker daemon") + } cmd := exec.Command(d.NodeConfig.OCIBinary, "kill", d.MachineName) if err := cmd.Run(); err != nil { return errors.Wrapf(err, "killing kic node %s", d.MachineName) @@ -217,6 +240,10 @@ func (d *Driver) Kill() error { // Remove will delete the Kic Node Container func (d *Driver) Remove() error { + if err := oci.PointToHostDockerDaemon(); err != nil { + return errors.Wrap(err, "point host docker daemon") + } + if _, err := oci.ContainerID(d.OCIBinary, d.MachineName); err != nil { log.Warnf("could not find the container %s to remove it.", d.MachineName) } @@ -234,13 +261,14 @@ func (d *Driver) Remove() error { // Restart a host func (d *Driver) Restart() error { + if err := oci.PointToHostDockerDaemon(); err != nil { + return errors.Wrap(err, "point host docker daemon") + } s, err := d.GetState() if err != nil { return errors.Wrap(err, "get kic state") } switch s { - case state.Paused: - return d.Unpause() case state.Stopped: return d.Start() case state.Running, state.Error: @@ -256,18 +284,12 @@ func (d *Driver) Restart() error { return fmt.Errorf("restarted not implemented for kic state %s yet", s) } -// Unpause a kic container -func (d *Driver) Unpause() error { - cmd := exec.Command(d.NodeConfig.OCIBinary, "unpause", d.MachineName) - if err := cmd.Run(); err != nil { - return errors.Wrapf(err, "unpausing %s", d.MachineName) - } - return nil -} - // Start a _stopped_ kic container // not meant to be used for Create(). func (d *Driver) Start() error { + if err := oci.PointToHostDockerDaemon(); err != nil { + return errors.Wrap(err, "point host docker daemon") + } s, err := d.GetState() if err != nil { return errors.Wrap(err, "get kic state") @@ -285,6 +307,9 @@ func (d *Driver) Start() error { // Stop a host gracefully, including any containers that we are managing. func (d *Driver) Stop() error { + if err := oci.PointToHostDockerDaemon(); err != nil { + return errors.Wrap(err, "point host docker daemon") + } cmd := exec.Command(d.NodeConfig.OCIBinary, "stop", d.MachineName) if err := cmd.Run(); err != nil { return errors.Wrapf(err, "stopping %s", d.MachineName) diff --git a/pkg/drivers/kic/oci/info.go b/pkg/drivers/kic/oci/info.go new file mode 100644 index 0000000000..3245bee2a6 --- /dev/null +++ b/pkg/drivers/kic/oci/info.go @@ -0,0 +1,245 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package oci + +import ( + "encoding/json" + "os/exec" + "strings" + "time" + + "github.com/pkg/errors" +) + +// SysInfo Info represents common system Information between docker and podman that minikube cares +type SysInfo struct { + CPUs int // CPUs is Number of CPUs + TotalMemory int64 // TotalMemory Total available ram +} + +// DaemonInfo returns common docker/podman daemon system info that minikube cares about +func DaemonInfo(ociBin string) (SysInfo, error) { + var info SysInfo + if ociBin == Podman { + p, err := podmanSystemInfo() + info.CPUs = p.Host.Cpus + info.TotalMemory = p.Host.MemTotal + return info, err + } + d, err := dockerSystemInfo() + info.CPUs = d.NCPU + info.TotalMemory = d.MemTotal + return info, err +} + +// dockerSysInfo represents the output of docker system info --format '{{json .}}' +type dockerSysInfo struct { + ID string `json:"ID"` + Containers int `json:"Containers"` + ContainersRunning int `json:"ContainersRunning"` + ContainersPaused int `json:"ContainersPaused"` + ContainersStopped int `json:"ContainersStopped"` + Images int `json:"Images"` + Driver string `json:"Driver"` + DriverStatus [][]string `json:"DriverStatus"` + SystemStatus interface{} `json:"SystemStatus"` + Plugins struct { + Volume []string `json:"Volume"` + Network []string `json:"Network"` + Authorization interface{} `json:"Authorization"` + Log []string `json:"Log"` + } `json:"Plugins"` + MemoryLimit bool `json:"MemoryLimit"` + SwapLimit bool `json:"SwapLimit"` + KernelMemory bool `json:"KernelMemory"` + KernelMemoryTCP bool `json:"KernelMemoryTCP"` + CPUCfsPeriod bool `json:"CpuCfsPeriod"` + CPUCfsQuota bool `json:"CpuCfsQuota"` + CPUShares bool `json:"CPUShares"` + CPUSet bool `json:"CPUSet"` + PidsLimit bool `json:"PidsLimit"` + IPv4Forwarding bool `json:"IPv4Forwarding"` + BridgeNfIptables bool `json:"BridgeNfIptables"` + BridgeNfIP6Tables bool `json:"BridgeNfIp6tables"` + Debug bool `json:"Debug"` + NFd int `json:"NFd"` + OomKillDisable bool `json:"OomKillDisable"` + NGoroutines int `json:"NGoroutines"` + SystemTime time.Time `json:"SystemTime"` + LoggingDriver string `json:"LoggingDriver"` + CgroupDriver string `json:"CgroupDriver"` + NEventsListener int `json:"NEventsListener"` + KernelVersion string `json:"KernelVersion"` + OperatingSystem string `json:"OperatingSystem"` + OSType string `json:"OSType"` + Architecture string `json:"Architecture"` + IndexServerAddress string `json:"IndexServerAddress"` + RegistryConfig struct { + AllowNondistributableArtifactsCIDRs []interface{} `json:"AllowNondistributableArtifactsCIDRs"` + AllowNondistributableArtifactsHostnames []interface{} `json:"AllowNondistributableArtifactsHostnames"` + InsecureRegistryCIDRs []string `json:"InsecureRegistryCIDRs"` + IndexConfigs struct { + DockerIo struct { + Name string `json:"Name"` + Mirrors []interface{} `json:"Mirrors"` + Secure bool `json:"Secure"` + Official bool `json:"Official"` + } `json:"docker.io"` + } `json:"IndexConfigs"` + Mirrors []interface{} `json:"Mirrors"` + } `json:"RegistryConfig"` + NCPU int `json:"NCPU"` + MemTotal int64 `json:"MemTotal"` + GenericResources interface{} `json:"GenericResources"` + DockerRootDir string `json:"DockerRootDir"` + HTTPProxy string `json:"HttpProxy"` + HTTPSProxy string `json:"HttpsProxy"` + NoProxy string `json:"NoProxy"` + Name string `json:"Name"` + Labels []interface{} `json:"Labels"` + ExperimentalBuild bool `json:"ExperimentalBuild"` + ServerVersion string `json:"ServerVersion"` + ClusterStore string `json:"ClusterStore"` + ClusterAdvertise string `json:"ClusterAdvertise"` + Runtimes struct { + Runc struct { + Path string `json:"path"` + } `json:"runc"` + } `json:"Runtimes"` + DefaultRuntime string `json:"DefaultRuntime"` + Swarm struct { + NodeID string `json:"NodeID"` + NodeAddr string `json:"NodeAddr"` + LocalNodeState string `json:"LocalNodeState"` + ControlAvailable bool `json:"ControlAvailable"` + Error string `json:"Error"` + RemoteManagers interface{} `json:"RemoteManagers"` + } `json:"Swarm"` + LiveRestoreEnabled bool `json:"LiveRestoreEnabled"` + Isolation string `json:"Isolation"` + InitBinary string `json:"InitBinary"` + ContainerdCommit struct { + ID string `json:"ID"` + Expected string `json:"Expected"` + } `json:"ContainerdCommit"` + RuncCommit struct { + ID string `json:"ID"` + Expected string `json:"Expected"` + } `json:"RuncCommit"` + InitCommit struct { + ID string `json:"ID"` + Expected string `json:"Expected"` + } `json:"InitCommit"` + SecurityOptions []string `json:"SecurityOptions"` + ProductLicense string `json:"ProductLicense"` + Warnings interface{} `json:"Warnings"` + ClientInfo struct { + Debug bool `json:"Debug"` + Plugins []interface{} `json:"Plugins"` + Warnings interface{} `json:"Warnings"` + } `json:"ClientInfo"` +} + +// podmanSysInfo represents the output of podman system info --format '{{json .}}' +type podmanSysInfo struct { + Host struct { + BuildahVersion string `json:"BuildahVersion"` + CgroupVersion string `json:"CgroupVersion"` + Conmon struct { + Package string `json:"package"` + Path string `json:"path"` + Version string `json:"version"` + } `json:"Conmon"` + Distribution struct { + Distribution string `json:"distribution"` + Version string `json:"version"` + } `json:"Distribution"` + MemFree int `json:"MemFree"` + MemTotal int64 `json:"MemTotal"` + OCIRuntime struct { + Name string `json:"name"` + Package string `json:"package"` + Path string `json:"path"` + Version string `json:"version"` + } `json:"OCIRuntime"` + SwapFree int `json:"SwapFree"` + SwapTotal int `json:"SwapTotal"` + Arch string `json:"arch"` + Cpus int `json:"cpus"` + Eventlogger string `json:"eventlogger"` + Hostname string `json:"hostname"` + Kernel string `json:"kernel"` + Os string `json:"os"` + Rootless bool `json:"rootless"` + Uptime string `json:"uptime"` + } `json:"host"` + Registries struct { + Search []string `json:"search"` + } `json:"registries"` + Store struct { + ConfigFile string `json:"ConfigFile"` + ContainerStore struct { + Number int `json:"number"` + } `json:"ContainerStore"` + GraphDriverName string `json:"GraphDriverName"` + GraphOptions struct { + } `json:"GraphOptions"` + GraphRoot string `json:"GraphRoot"` + GraphStatus struct { + BackingFilesystem string `json:"Backing Filesystem"` + NativeOverlayDiff string `json:"Native Overlay Diff"` + SupportsDType string `json:"Supports d_type"` + UsingMetacopy string `json:"Using metacopy"` + } `json:"GraphStatus"` + ImageStore struct { + Number int `json:"number"` + } `json:"ImageStore"` + RunRoot string `json:"RunRoot"` + VolumePath string `json:"VolumePath"` + } `json:"store"` +} + +// dockerSystemInfo returns docker system info --format '{{json .}}' +func dockerSystemInfo() (dockerSysInfo, error) { + var ds dockerSysInfo + if err := PointToHostDockerDaemon(); err != nil { + return ds, errors.Wrap(err, "point host docker-daemon") + } + cmd := exec.Command(Docker, "system", "info", "--format", "{{json .}}") + out, err := cmd.CombinedOutput() + if err != nil { + return ds, errors.Wrap(err, "get docker system info") + } + if err := json.Unmarshal([]byte(strings.TrimSpace(string(out))), &ds); err != nil { + return ds, errors.Wrapf(err, "unmarshal docker system info") + } + return ds, nil +} + +// podmanSysInfo returns podman system info --format '{{json .}}' +func podmanSystemInfo() (podmanSysInfo, error) { + var ps podmanSysInfo + cmd := exec.Command(Podman, "system", "info", "--format", "'{{json .}}'") + out, err := cmd.CombinedOutput() + if err != nil { + return ps, errors.Wrap(err, "get podman system info") + } + if err := json.Unmarshal([]byte(strings.TrimSpace(string(out))), &ps); err != nil { + return ps, errors.Wrapf(err, "unmarshal podman system info") + } + return ps, nil +} diff --git a/pkg/drivers/kic/oci/network.go b/pkg/drivers/kic/oci/network.go index 5e27528b5f..bfb602dcde 100644 --- a/pkg/drivers/kic/oci/network.go +++ b/pkg/drivers/kic/oci/network.go @@ -21,6 +21,7 @@ import ( "net" "os/exec" "runtime" + "strconv" "strings" "github.com/golang/glog" @@ -43,7 +44,7 @@ func RoutableHostIPFromInside(ociBin string, containerName string) (net.IP, erro // digDNS will get the IP record for a dns func digDNS(ociBin, containerName, dns string) (net.IP, error) { if err := PointToHostDockerDaemon(); err != nil { - return nil, errors.Wrap(err, "point host docker-daemon") + return nil, errors.Wrap(err, "point host docker daemon") } cmd := exec.Command(ociBin, "exec", "-t", containerName, "dig", "+short", dns) out, err := cmd.CombinedOutput() @@ -59,7 +60,7 @@ func digDNS(ociBin, containerName, dns string) (net.IP, error) { // gets the ip from user's host docker func dockerGatewayIP() (net.IP, error) { if err := PointToHostDockerDaemon(); err != nil { - return nil, errors.Wrap(err, "point host docker-daemon") + return nil, errors.Wrap(err, "point host docker daemon") } cmd := exec.Command(Docker, "network", "ls", "--filter", "name=bridge", "--format", "{{.ID}}") out, err := cmd.CombinedOutput() @@ -77,3 +78,82 @@ func dockerGatewayIP() (net.IP, error) { glog.Infof("got host ip for mount in container by inspect docker network: %s", ip.String()) return ip, nil } + +// HostPortBinding will return port mapping for a container using cli. +// example : HostPortBinding("docker", "minikube", "22") +// will return the docker assigned port: +// 32769, nil +// only supports TCP ports +func HostPortBinding(ociBinary string, ociID string, contPort int) (int, error) { + if err := PointToHostDockerDaemon(); err != nil { + return 0, errors.Wrap(err, "point host docker daemon") + } + var out []byte + var err error + if ociBinary == Podman { + //podman inspect -f "{{range .NetworkSettings.Ports}}{{if eq .ContainerPort "80"}}{{.HostPort}}{{end}}{{end}}" + cmd := exec.Command(ociBinary, "inspect", "-f", fmt.Sprintf("{{range .NetworkSettings.Ports}}{{if eq .ContainerPort %s}}{{.HostPort}}{{end}}{{end}}", fmt.Sprint(contPort)), ociID) + out, err = cmd.CombinedOutput() + if err != nil { + return 0, errors.Wrapf(err, "get host-bind port %d for %q, output %s", contPort, ociID, out) + } + } else { + cmd := exec.Command(ociBinary, "inspect", "-f", fmt.Sprintf("'{{(index (index .NetworkSettings.Ports \"%d/tcp\") 0).HostPort}}'", contPort), ociID) + out, err = cmd.CombinedOutput() + if err != nil { + return 0, errors.Wrapf(err, "get host-bind port %d for %q, output %s", contPort, ociID, out) + } + } + + o := strings.TrimSpace(string(out)) + o = strings.Trim(o, "'") + p, err := strconv.Atoi(o) + if err != nil { + return p, errors.Wrapf(err, "convert host-port %q to number", p) + } + return p, nil +} + +// ContainerIPs returns ipv4,ipv6, error of a container by their name +func ContainerIPs(ociBinary string, name string) (string, string, error) { + if ociBinary == Podman { + return podmanConttainerIP(name) + } + return dockerContainerIP(name) +} + +// podmanConttainerIP returns ipv4, ipv6 of container or error +func podmanConttainerIP(name string) (string, string, error) { + cmd := exec.Command(Podman, "inspect", + "-f", "{{.NetworkSettings.IPAddress}}", + name) + out, err := cmd.CombinedOutput() + if err != nil { + return "", "", errors.Wrapf(err, "podman inspect ip %s", name) + } + output := strings.TrimSpace(string(out)) + if err == nil && output == "" { // podman returns empty for 127.0.0.1 + return DefaultBindIPV4, "", nil + } + return output, "", nil +} + +// dockerContainerIP returns ipv4, ipv6 of container or error +func dockerContainerIP(name string) (string, string, error) { + if err := PointToHostDockerDaemon(); err != nil { + return "", "", errors.Wrap(err, "point host docker daemon") + } + // retrieve the IP address of the node using docker inspect + lines, err := inspect(Docker, name, "{{range .NetworkSettings.Networks}}{{.IPAddress}},{{.GlobalIPv6Address}}{{end}}") + if err != nil { + return "", "", errors.Wrap(err, "inspecting NetworkSettings.Networks") + } + if len(lines) != 1 { + return "", "", errors.Errorf("IPs output should only be one line, got %d lines", len(lines)) + } + ips := strings.Split(lines[0], ",") + if len(ips) != 2 { + return "", "", errors.Errorf("container addresses should have 2 values, got %d values: %+v", len(ips), ips) + } + return ips[0], ips[1], nil +} diff --git a/pkg/drivers/kic/oci/oci.go b/pkg/drivers/kic/oci/oci.go index 630b6db4b9..22473fb895 100644 --- a/pkg/drivers/kic/oci/oci.go +++ b/pkg/drivers/kic/oci/oci.go @@ -17,9 +17,10 @@ limitations under the License. package oci import ( + "context" "os" "path/filepath" - "strconv" + "time" "bufio" "bytes" @@ -34,13 +35,13 @@ import ( "strings" ) -// DeleteAllContainersByLabel deletes all containers that have a specific label +// DeleteContainersByLabel deletes all containers that have a specific label // if there no containers found with the given label, it will return nil -func DeleteAllContainersByLabel(ociBin string, label string) []error { +func DeleteContainersByLabel(ociBin string, label string) []error { var deleteErrs []error if ociBin == Docker { if err := PointToHostDockerDaemon(); err != nil { - return []error{errors.Wrap(err, "point host docker-daemon")} + return []error{errors.Wrap(err, "point host docker daemon")} } } cs, err := listContainersByLabel(ociBin, label) @@ -51,10 +52,19 @@ func DeleteAllContainersByLabel(ociBin string, label string) []error { return nil } for _, c := range cs { + _, err := ContainerStatus(ociBin, c) + // only try to delete if docker/podman inspect returns + // if it doesn't it means docker daemon is stuck and needs restart + if err != nil { + deleteErrs = append(deleteErrs, errors.Wrapf(err, "delete container %s: %s daemon is stuck. please try again!", c, ociBin)) + glog.Errorf("%s daemon seems to be stuck. Please try restarting your %s.", ociBin, ociBin) + continue + } cmd := exec.Command(ociBin, "rm", "-f", "-v", c) if out, err := cmd.CombinedOutput(); err != nil { deleteErrs = append(deleteErrs, errors.Wrapf(err, "delete container %s: output %s", c, out)) } + } return deleteErrs } @@ -62,7 +72,7 @@ func DeleteAllContainersByLabel(ociBin string, label string) []error { // CreateContainerNode creates a new container node func CreateContainerNode(p CreateParams) error { if err := PointToHostDockerDaemon(); err != nil { - return errors.Wrap(err, "point host docker-daemon") + return errors.Wrap(err, "point host docker daemon") } runArgs := []string{ @@ -87,6 +97,8 @@ func CreateContainerNode(p CreateParams) error { "--label", p.ClusterLabel, // label the node with the role ID "--label", fmt.Sprintf("%s=%s", nodeRoleLabelKey, p.Role), + // label th enode wuth the node ID + "--label", p.NodeLabel, } if p.OCIBinary == Podman { // enable execing in /var @@ -99,7 +111,7 @@ func CreateContainerNode(p CreateParams) error { runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var:exec", hostVarVolPath)) } if p.OCIBinary == Docker { - if err := createDockerVolume(p.Name); err != nil { + if err := createDockerVolume(p.Name, p.Name); err != nil { return errors.Wrapf(err, "creating volume for %s container", p.Name) } glog.Infof("Successfully created a docker volume %s", p.Name) @@ -141,7 +153,7 @@ func CreateContainerNode(p CreateParams) error { // CreateContainer creates a container with "docker/podman run" func createContainer(ociBinary string, image string, opts ...createOpt) ([]string, error) { if err := PointToHostDockerDaemon(); err != nil { - return nil, errors.Wrap(err, "point host docker-daemon") + return nil, errors.Wrap(err, "point host docker daemon") } o := &createOpts{} @@ -185,7 +197,7 @@ func createContainer(ociBinary string, image string, opts ...createOpt) ([]strin // Copy copies a local asset into the container func Copy(ociBinary string, ociID string, targetDir string, fName string) error { if err := PointToHostDockerDaemon(); err != nil { - return errors.Wrap(err, "point host docker-daemon") + return errors.Wrap(err, "point host docker daemon") } if _, err := os.Stat(fName); os.IsNotExist(err) { return errors.Wrapf(err, "error source %s does not exist", fName) @@ -199,89 +211,10 @@ func Copy(ociBinary string, ociID string, targetDir string, fName string) error return nil } -// HostPortBinding will return port mapping for a container using cli. -// example : HostPortBinding("docker", "minikube", "22") -// will return the docker assigned port: -// 32769, nil -// only supports TCP ports -func HostPortBinding(ociBinary string, ociID string, contPort int) (int, error) { - if err := PointToHostDockerDaemon(); err != nil { - return 0, errors.Wrap(err, "point host docker-daemon") - } - var out []byte - var err error - if ociBinary == Podman { - //podman inspect -f "{{range .NetworkSettings.Ports}}{{if eq .ContainerPort "80"}}{{.HostPort}}{{end}}{{end}}" - cmd := exec.Command(ociBinary, "inspect", "-f", fmt.Sprintf("{{range .NetworkSettings.Ports}}{{if eq .ContainerPort %s}}{{.HostPort}}{{end}}{{end}}", fmt.Sprint(contPort)), ociID) - out, err = cmd.CombinedOutput() - if err != nil { - return 0, errors.Wrapf(err, "get host-bind port %d for %q, output %s", contPort, ociID, out) - } - } else { - cmd := exec.Command(ociBinary, "inspect", "-f", fmt.Sprintf("'{{(index (index .NetworkSettings.Ports \"%d/tcp\") 0).HostPort}}'", contPort), ociID) - out, err = cmd.CombinedOutput() - if err != nil { - return 0, errors.Wrapf(err, "get host-bind port %d for %q, output %s", contPort, ociID, out) - } - } - - o := strings.TrimSpace(string(out)) - o = strings.Trim(o, "'") - p, err := strconv.Atoi(o) - if err != nil { - return p, errors.Wrapf(err, "convert host-port %q to number", p) - } - return p, nil -} - -// ContainerIPs returns ipv4,ipv6, error of a container by their name -func ContainerIPs(ociBinary string, name string) (string, string, error) { - if ociBinary == Podman { - return podmanConttainerIP(name) - } - return dockerContainerIP(name) -} - -// podmanConttainerIP returns ipv4, ipv6 of container or error -func podmanConttainerIP(name string) (string, string, error) { - cmd := exec.Command(Podman, "inspect", - "-f", "{{.NetworkSettings.IPAddress}}", - name) - out, err := cmd.CombinedOutput() - if err != nil { - return "", "", errors.Wrapf(err, "podman inspect ip %s", name) - } - output := strings.TrimSpace(string(out)) - if err == nil && output == "" { // podman returns empty for 127.0.0.1 - return DefaultBindIPV4, "", nil - } - return output, "", nil -} - -// dockerContainerIP returns ipv4, ipv6 of container or error -func dockerContainerIP(name string) (string, string, error) { - if err := PointToHostDockerDaemon(); err != nil { - return "", "", errors.Wrap(err, "point host docker-daemon") - } - // retrieve the IP address of the node using docker inspect - lines, err := inspect(Docker, name, "{{range .NetworkSettings.Networks}}{{.IPAddress}},{{.GlobalIPv6Address}}{{end}}") - if err != nil { - return "", "", errors.Wrap(err, "inspecting NetworkSettings.Networks") - } - if len(lines) != 1 { - return "", "", errors.Errorf("IPs output should only be one line, got %d lines", len(lines)) - } - ips := strings.Split(lines[0], ",") - if len(ips) != 2 { - return "", "", errors.Errorf("container addresses should have 2 values, got %d values: %+v", len(ips), ips) - } - return ips[0], ips[1], nil -} - // ContainerID returns id of a container name func ContainerID(ociBinary string, nameOrID string) (string, error) { if err := PointToHostDockerDaemon(); err != nil { - return "", errors.Wrap(err, "point host docker-daemon") + return "", errors.Wrap(err, "point host docker daemon") } cmd := exec.Command(ociBinary, "inspect", "-f", "{{.Id}}", nameOrID) id, err := cmd.CombinedOutput() @@ -299,7 +232,7 @@ func ListOwnedContainers(ociBinary string) ([]string, error) { // inspect return low-level information on containers func inspect(ociBinary string, containerNameOrID, format string) ([]string, error) { if err := PointToHostDockerDaemon(); err != nil { - return nil, errors.Wrap(err, "point host docker-daemon") + return nil, errors.Wrap(err, "point host docker daemon") } cmd := exec.Command(ociBinary, "inspect", "-f", format, @@ -365,7 +298,7 @@ func generateMountBindings(mounts ...Mount) []string { // isUsernsRemapEnabled checks if userns-remap is enabled in docker func isUsernsRemapEnabled(ociBinary string) (bool, error) { if err := PointToHostDockerDaemon(); err != nil { - return false, errors.Wrap(err, "point host docker-daemon") + return false, errors.Wrap(err, "point host docker daemon") } cmd := exec.Command(ociBinary, "info", "--format", "'{{json .SecurityOptions}}'") var buff bytes.Buffer @@ -427,9 +360,12 @@ func withPortMappings(portMappings []PortMapping) createOpt { // listContainersByLabel returns all the container names with a specified label func listContainersByLabel(ociBinary string, label string) ([]string, error) { if err := PointToHostDockerDaemon(); err != nil { - return nil, errors.Wrap(err, "point host docker-daemon") + return nil, errors.Wrap(err, "point host docker daemon") } - cmd := exec.Command(ociBinary, "ps", "-a", "--filter", fmt.Sprintf("label=%s", label), "--format", "{{.Names}}") + // allow no more than 5 seconds for docker ps + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, ociBinary, "ps", "-a", "--filter", fmt.Sprintf("label=%s", label), "--format", "{{.Names}}") stdout, err := cmd.Output() s := bufio.NewScanner(bytes.NewReader(stdout)) var names []string @@ -439,7 +375,6 @@ func listContainersByLabel(ociBinary string, label string) ([]string, error) { names = append(names, n) } } - return names, err } @@ -448,7 +383,7 @@ func listContainersByLabel(ociBinary string, label string) ([]string, error) { func PointToHostDockerDaemon() error { p := os.Getenv(constants.MinikubeActiveDockerdEnv) if p != "" { - glog.Infof("shell is pointing to docker inside minikube. will unset to use host") + glog.Infof("shell is pointing to dockerd inside minikube. will unset to use host") } for i := range constants.DockerDaemonEnvs { @@ -461,3 +396,25 @@ func PointToHostDockerDaemon() error { } return nil } + +// ContainerStatus returns status of a container running,exited,... +func ContainerStatus(ociBin string, name string) (string, error) { + if ociBin == Docker { + if err := PointToHostDockerDaemon(); err != nil { + return "", errors.Wrap(err, "point host docker daemon") + } + } + // allow no more than 2 seconds for this. when this takes long this means deadline passed + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, ociBin, "inspect", name, "--format={{.State.Status}}") + out, err := cmd.CombinedOutput() + if ctx.Err() == context.DeadlineExceeded { + glog.Warningf("%s inspect %s took longer than normal. Restarting your %s daemon might fix this issue.", ociBin, name, ociBin) + return strings.TrimSpace(string(out)), fmt.Errorf("inspect %s timeout", name) + } + if err != nil { + return string(out), errors.Wrapf(err, "inspecting container: output %s", out) + } + return strings.TrimSpace(string(out)), nil +} diff --git a/pkg/drivers/kic/oci/types.go b/pkg/drivers/kic/oci/types.go index d2b6eca033..8c43ce7d8b 100644 --- a/pkg/drivers/kic/oci/types.go +++ b/pkg/drivers/kic/oci/types.go @@ -25,6 +25,8 @@ const ( Podman = "podman" // ProfileLabelKey is applied to any container or volume created by a specific minikube profile name.minikube.sigs.k8s.io=PROFILE_NAME ProfileLabelKey = "name.minikube.sigs.k8s.io" + // NodeLabelKey is applied to each volume so it can be referred to by name + NodeLabelKey = "mode.minikube.sigs.k8s.io" // NodeRoleKey is used to identify if it is control plane or worker nodeRoleLabelKey = "role.minikube.sigs.k8s.io" // CreatedByLabelKey is applied to any container/volume that is created by minikube created_by.minikube.sigs.k8s.io=true @@ -35,7 +37,8 @@ const ( type CreateParams struct { Name string // used for container name and hostname Image string // container image to use to create the node. - ClusterLabel string // label the containers we create using minikube so we can clean up + ClusterLabel string // label the clusters we create using minikube so we can clean up + NodeLabel string // label the nodes so we can clean up by node name Role string // currently only role supported is control-plane Mounts []Mount // volume mounts APIServerPort int // kubernetes api server port diff --git a/pkg/drivers/kic/oci/volumes.go b/pkg/drivers/kic/oci/volumes.go index a06f471d04..2163d3bf65 100644 --- a/pkg/drivers/kic/oci/volumes.go +++ b/pkg/drivers/kic/oci/volumes.go @@ -19,9 +19,11 @@ package oci import ( "bufio" "bytes" + "context" "fmt" "os/exec" "strings" + "time" "github.com/golang/glog" "github.com/pkg/errors" @@ -34,7 +36,7 @@ func DeleteAllVolumesByLabel(ociBin string, label string) []error { glog.Infof("trying to delete all %s volumes with label %s", ociBin, label) if ociBin == Docker { if err := PointToHostDockerDaemon(); err != nil { - return []error{errors.Wrap(err, "point host docker-daemon")} + return []error{errors.Wrap(err, "point host docker daemon")} } } @@ -42,9 +44,15 @@ func DeleteAllVolumesByLabel(ociBin string, label string) []error { if err != nil { return []error{fmt.Errorf("listing volumes by label %q: %v", label, err)} } - for _, v := range vs { - cmd := exec.Command(ociBin, "volume", "rm", "--force", v) + // allow no more than 3 seconds for this. when this takes long this means deadline passed + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, ociBin, "volume", "rm", "--force", v) + if ctx.Err() == context.DeadlineExceeded { + glog.Warningf("removing volume with label %s took longer than normal. Restarting your %s daemon might fix this issue.", label, ociBin) + deleteErrs = append(deleteErrs, fmt.Errorf("delete deadline exceeded for %s", label)) + } if out, err := cmd.CombinedOutput(); err != nil { deleteErrs = append(deleteErrs, fmt.Errorf("deleting volume %s: output: %s", v, string(out))) } @@ -60,15 +68,22 @@ func PruneAllVolumesByLabel(ociBin string, label string) []error { glog.Infof("trying to prune all %s volumes with label %s", ociBin, label) if ociBin == Docker { if err := PointToHostDockerDaemon(); err != nil { - return []error{errors.Wrap(err, "point host docker-daemon")} + return []error{errors.Wrap(err, "point host docker daemon")} } } + // allow no more than 3 seconds for this. when this takes long this means deadline passed + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() // try to prune afterwards just in case delete didn't go through - cmd := exec.Command(ociBin, "volume", "prune", "-f", "--filter", "label="+label) + cmd := exec.CommandContext(ctx, ociBin, "volume", "prune", "-f", "--filter", "label="+label) if out, err := cmd.CombinedOutput(); err != nil { deleteErrs = append(deleteErrs, errors.Wrapf(err, "prune volume by label %s: %s", label, string(out))) } + if ctx.Err() == context.DeadlineExceeded { + glog.Warningf("pruning volume with label %s took longer than normal. Restarting your %s daemon might fix this issue.", label, ociBin) + deleteErrs = append(deleteErrs, fmt.Errorf("prune deadline exceeded for %s", label)) + } return deleteErrs } @@ -88,14 +103,27 @@ func allVolumesByLabel(ociBin string, label string) ([]string, error) { return vols, err } -// createDockerVolume creates a docker volume to be attached to the container with correct labels and prefixes based on profile name -// Caution ! if volume already exists does NOT return an error and will not apply the minikube labels on it. -// TODO: this should be fixed as a part of https://github.com/kubernetes/minikube/issues/6530 -func createDockerVolume(name string) error { +// ExtractTarballToVolume runs a docker image imageName which extracts the tarball at tarballPath +// to the volume named volumeName +func ExtractTarballToVolume(tarballPath, volumeName, imageName string) error { if err := PointToHostDockerDaemon(); err != nil { return errors.Wrap(err, "point host docker-daemon") } - cmd := exec.Command(Docker, "volume", "create", name, "--label", fmt.Sprintf("%s=%s", ProfileLabelKey, name), "--label", fmt.Sprintf("%s=%s", CreatedByLabelKey, "true")) + cmd := exec.Command(Docker, "run", "--rm", "--entrypoint", "/usr/bin/tar", "-v", fmt.Sprintf("%s:/preloaded.tar:ro", tarballPath), "-v", fmt.Sprintf("%s:/extractDir", volumeName), imageName, "-I", "lz4", "-xvf", "/preloaded.tar", "-C", "/extractDir") + if out, err := cmd.CombinedOutput(); err != nil { + return errors.Wrapf(err, "output %s", string(out)) + } + return nil +} + +// createDockerVolume creates a docker volume to be attached to the container with correct labels and prefixes based on profile name +// Caution ! if volume already exists does NOT return an error and will not apply the minikube labels on it. +// TODO: this should be fixed as a part of https://github.com/kubernetes/minikube/issues/6530 +func createDockerVolume(profile string, nodeName string) error { + if err := PointToHostDockerDaemon(); err != nil { + return errors.Wrap(err, "point host docker daemon") + } + cmd := exec.Command(Docker, "volume", "create", nodeName, "--label", fmt.Sprintf("%s=%s", ProfileLabelKey, profile), "--label", fmt.Sprintf("%s=%s", CreatedByLabelKey, "true")) if out, err := cmd.CombinedOutput(); err != nil { return errors.Wrapf(err, "output %s", string(out)) } diff --git a/pkg/drivers/kic/types.go b/pkg/drivers/kic/types.go index e5b7983a84..32e2950396 100644 --- a/pkg/drivers/kic/types.go +++ b/pkg/drivers/kic/types.go @@ -46,14 +46,16 @@ var ( // Config is configuration for the kic driver used by registry type Config struct { - 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 - StorePath string // libmachine store path - OCIBinary string // oci tool to use (docker, podman,...) - ImageDigest string // image name with sha to use for the node - Mounts []oci.Mount // mounts - APIServerPort int // kubernetes api server port inside the container - PortMappings []oci.PortMapping // container port mappings - Envs map[string]string // key,value of environment variables passed to the node + 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 + StorePath string // libmachine store path + OCIBinary string // oci tool to use (docker, podman,...) + ImageDigest string // image name with sha to use for the node + Mounts []oci.Mount // mounts + APIServerPort int // kubernetes api server port inside the container + PortMappings []oci.PortMapping // container port mappings + Envs map[string]string // key,value of environment variables passed to the node + KubernetesVersion string // kubernetes version to install + ContainerRuntime string // container runtime kic is running } diff --git a/pkg/minikube/bootstrapper/bsutil/binaries.go b/pkg/minikube/bootstrapper/bsutil/binaries.go index 532be8a7ad..32b9a166a2 100644 --- a/pkg/minikube/bootstrapper/bsutil/binaries.go +++ b/pkg/minikube/bootstrapper/bsutil/binaries.go @@ -18,23 +18,34 @@ limitations under the License. package bsutil import ( + "fmt" "os/exec" "path" "runtime" + "strings" + "github.com/golang/glog" "github.com/pkg/errors" "golang.org/x/sync/errgroup" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/vmpath" ) // TransferBinaries transfers all required Kubernetes binaries func TransferBinaries(cfg config.KubernetesConfig, c command.Runner) error { + ok, err := binariesExist(cfg, c) + if err == nil && ok { + glog.Info("Found k8s binaries, skipping transfer") + return nil + } + glog.Infof("Didn't find k8s binaries: %v\nInitiating transfer...", err) + dir := binRoot(cfg.KubernetesVersion) - _, err := c.RunCmd(exec.Command("sudo", "mkdir", "-p", dir)) + _, err = c.RunCmd(exec.Command("sudo", "mkdir", "-p", dir)) if err != nil { return err } @@ -43,7 +54,7 @@ func TransferBinaries(cfg config.KubernetesConfig, c command.Runner) error { for _, name := range constants.KubernetesReleaseBinaries { name := name g.Go(func() error { - src, err := machine.CacheBinary(name, cfg.KubernetesVersion, "linux", runtime.GOARCH) + src, err := download.Binary(name, cfg.KubernetesVersion, "linux", runtime.GOARCH) if err != nil { return errors.Wrapf(err, "downloading %s", name) } @@ -58,6 +69,26 @@ func TransferBinaries(cfg config.KubernetesConfig, c command.Runner) error { return g.Wait() } +// binariesExist returns true if the binaries already exist +func binariesExist(cfg config.KubernetesConfig, c command.Runner) (bool, error) { + dir := binRoot(cfg.KubernetesVersion) + rr, err := c.RunCmd(exec.Command("sudo", "ls", dir)) + stdout := rr.Stdout.String() + if err != nil { + return false, err + } + foundBinaries := map[string]struct{}{} + for _, binary := range strings.Split(stdout, "\n") { + foundBinaries[binary] = struct{}{} + } + for _, name := range constants.KubernetesReleaseBinaries { + if _, ok := foundBinaries[name]; !ok { + return false, fmt.Errorf("didn't find preexisting %s", name) + } + } + return true, nil +} + // binRoot returns the persistent path binaries are stored in func binRoot(version string) string { return path.Join(vmpath.GuestPersistentDir, "binaries", version) diff --git a/pkg/minikube/bootstrapper/bsutil/extraconfig.go b/pkg/minikube/bootstrapper/bsutil/extraconfig.go index 94851f6892..c6cf960141 100644 --- a/pkg/minikube/bootstrapper/bsutil/extraconfig.go +++ b/pkg/minikube/bootstrapper/bsutil/extraconfig.go @@ -70,6 +70,7 @@ var KubeadmExtraArgsWhitelist = map[int][]string{ "experimental-upload-certs", "certificate-key", "rootfs", + "skip-phases", }, KubeadmConfigParam: { "pod-network-cidr", diff --git a/pkg/minikube/bootstrapper/certs.go b/pkg/minikube/bootstrapper/certs.go index 7b634970a0..6146fbc634 100644 --- a/pkg/minikube/bootstrapper/certs.go +++ b/pkg/minikube/bootstrapper/certs.go @@ -132,9 +132,8 @@ func SetupCerts(cmd command.Runner, k8s config.KubernetesConfig, n config.Node) } } - // configure CA certificates - if err := configureCACerts(cmd, caCerts); err != nil { - return errors.Wrapf(err, "Configuring CA certs") + if err := installCertSymlinks(cmd, caCerts); err != nil { + return errors.Wrapf(err, "certificate symlinks") } return nil } @@ -320,9 +319,9 @@ func getSubjectHash(cr command.Runner, filePath string) (string, error) { return stringHash, nil } -// configureCACerts looks up and installs all uploaded PEM certificates in /usr/share/ca-certificates to system-wide certificate store (/etc/ssl/certs). +// installCertSymlinks installs certs in /usr/share/ca-certificates into system-wide certificate store (/etc/ssl/certs). // OpenSSL binary required in minikube ISO -func configureCACerts(cr command.Runner, caCerts map[string]string) error { +func installCertSymlinks(cr command.Runner, caCerts map[string]string) error { hasSSLBinary := true _, err := cr.RunCmd(exec.Command("openssl", "version")) if err != nil { @@ -336,7 +335,8 @@ func configureCACerts(cr command.Runner, caCerts map[string]string) error { for _, caCertFile := range caCerts { dstFilename := path.Base(caCertFile) certStorePath := path.Join(vmpath.GuestCertStoreDir, dstFilename) - cmd := fmt.Sprintf("test -f %s || ln -fs %s %s", caCertFile, certStorePath, caCertFile) + // If the cert really exists, add a named symlink + cmd := fmt.Sprintf("test -f %s && ln -fs %s %s", caCertFile, caCertFile, certStorePath) if _, err := cr.RunCmd(exec.Command("sudo", "/bin/bash", "-c", cmd)); err != nil { return errors.Wrapf(err, "create symlink for %s", caCertFile) } diff --git a/pkg/minikube/bootstrapper/certs_test.go b/pkg/minikube/bootstrapper/certs_test.go index a3448657d1..d92e174660 100644 --- a/pkg/minikube/bootstrapper/certs_test.go +++ b/pkg/minikube/bootstrapper/certs_test.go @@ -52,8 +52,8 @@ func TestSetupCerts(t *testing.T) { } expected := map[string]string{ - `sudo /bin/bash -c "test -f /usr/share/ca-certificates/mycert.pem || ln -fs /etc/ssl/certs/mycert.pem /usr/share/ca-certificates/mycert.pem"`: "-", - `sudo /bin/bash -c "test -f /usr/share/ca-certificates/minikubeCA.pem || ln -fs /etc/ssl/certs/minikubeCA.pem /usr/share/ca-certificates/minikubeCA.pem"`: "-", + `sudo /bin/bash -c "test -f /usr/share/ca-certificates/mycert.pem && ln -fs /usr/share/ca-certificates/mycert.pem /etc/ssl/certs/mycert.pem"`: "-", + `sudo /bin/bash -c "test -f /usr/share/ca-certificates/minikubeCA.pem && ln -fs /usr/share/ca-certificates/minikubeCA.pem /etc/ssl/certs/minikubeCA.pem"`: "-", } f := command.NewFakeCommandRunner() f.SetCommandToOutput(expected) diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 14aed83c6c..68d33b8eb7 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -36,7 +36,6 @@ import ( "github.com/docker/machine/libmachine/state" "github.com/golang/glog" "github.com/pkg/errors" - "github.com/spf13/viper" "k8s.io/client-go/kubernetes" kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/minikube/pkg/drivers/kic" @@ -65,7 +64,9 @@ type Bootstrapper struct { } // NewBootstrapper creates a new kubeadm.Bootstrapper -func NewBootstrapper(api libmachine.API, name string) (*Bootstrapper, error) { +// TODO(#6891): Remove node as an argument +func NewBootstrapper(api libmachine.API, cc config.ClusterConfig, n config.Node) (*Bootstrapper, error) { + name := driver.MachineName(cc, n) h, err := api.Load(name) if err != nil { return nil, errors.Wrap(err, "getting api client") @@ -74,7 +75,7 @@ func NewBootstrapper(api libmachine.API, name string) (*Bootstrapper, error) { if err != nil { return nil, errors.Wrap(err, "command runner") } - return &Bootstrapper{c: runner, contextName: viper.GetString(config.MachineProfile), k8sClient: nil}, nil + return &Bootstrapper{c: runner, contextName: cc.Name, k8sClient: nil}, nil } // GetKubeletStatus returns the kubelet status @@ -268,7 +269,7 @@ func (k *Bootstrapper) WaitForNode(cfg config.ClusterConfig, n config.Node, time port := cp.Port if driver.IsKIC(cfg.Driver) { ip = oci.DefaultBindIPV4 - port, err = oci.HostPortBinding(cfg.Driver, driver.MachineName(cfg.Name, n.Name), port) + port, err = oci.HostPortBinding(cfg.Driver, driver.MachineName(cfg, n), port) if err != nil { return errors.Wrapf(err, "get host-bind port %d for container %s", port, cfg.Name) } @@ -338,9 +339,9 @@ func (k *Bootstrapper) restartCluster(cfg config.ClusterConfig) error { port := n.Port if driver.IsKIC(cfg.Driver) { ip = oci.DefaultBindIPV4 - port, err = oci.HostPortBinding(cfg.Driver, driver.MachineName(cfg.Name, n.Name), port) + port, err = oci.HostPortBinding(cfg.Driver, driver.MachineName(cfg, n), port) if err != nil { - return errors.Wrapf(err, "get host-bind port %d for container %s", port, driver.MachineName(cfg.Name, n.Name)) + return errors.Wrapf(err, "get host-bind port %d for container %s", port, driver.MachineName(cfg, n)) } } client, err := k.client(ip, port) diff --git a/pkg/minikube/cluster/cache.go b/pkg/minikube/cluster/cache.go index 04e7c8b6c6..e918eb454e 100644 --- a/pkg/minikube/cluster/cache.go +++ b/pkg/minikube/cluster/cache.go @@ -24,8 +24,10 @@ import ( "github.com/spf13/viper" "golang.org/x/sync/errgroup" cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config" + "k8s.io/minikube/pkg/drivers/kic" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/image" "k8s.io/minikube/pkg/minikube/localpath" @@ -49,8 +51,7 @@ func BeginCacheRequiredImages(g *errgroup.Group, imageRepository string, k8sVers }) } -// HandleDownloadOnly handles the download-only parameter -func HandleDownloadOnly(cacheGroup *errgroup.Group, k8sVersion string) { +func handleDownloadOnly(cacheGroup, kicGroup *errgroup.Group, k8sVersion string) { // If --download-only, complete the remaining downloads and exit. if !viper.GetBool("download-only") { return @@ -62,6 +63,7 @@ func HandleDownloadOnly(cacheGroup *errgroup.Group, k8sVersion string) { exit.WithError("Failed to cache kubectl", err) } WaitCacheRequiredImages(cacheGroup) + waitDownloadKicArtifacts(kicGroup) if err := saveImagesToTarFromConfig(); err != nil { exit.WithError("Failed to cache images to tar", err) } @@ -77,7 +79,7 @@ func CacheKubectlBinary(k8sVerison string) (string, error) { binary = "kubectl.exe" } - return machine.CacheBinary(binary, k8sVerison, runtime.GOOS, runtime.GOARCH) + return download.Binary(binary, k8sVerison, runtime.GOOS, runtime.GOARCH) } // doCacheBinaries caches Kubernetes binaries in the foreground @@ -85,7 +87,33 @@ func doCacheBinaries(k8sVersion string) error { return machine.CacheBinariesForBootstrapper(k8sVersion, viper.GetString(cmdcfg.Bootstrapper)) } -// WaitCacheRequiredImages blocks until the required images are all cached. +// beginDownloadKicArtifacts downloads the kic image + preload tarball, returns true if preload is available +func beginDownloadKicArtifacts(g *errgroup.Group, k8sVersion, cRuntime string) bool { + glog.Info("Beginning downloading kic artifacts") + g.Go(func() error { + glog.Infof("Downloading %s to local daemon", kic.BaseImage) + return image.WriteImageToDaemon(kic.BaseImage) + }) + + if download.PreloadExists(k8sVersion, cRuntime) { + g.Go(func() error { + glog.Info("Caching tarball of preloaded images") + return download.Preload(k8sVersion, cRuntime) + }) + return true + } + return false +} + +func waitDownloadKicArtifacts(g *errgroup.Group) { + if err := g.Wait(); err != nil { + glog.Errorln("Error downloading kic artifacts: ", err) + return + } + glog.Info("Successfully downloaded all kic artifacts") +} + +// waitCacheRequiredImages blocks until the required images are all cached. func WaitCacheRequiredImages(g *errgroup.Group) { if !viper.GetBool(cacheImages) { return diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index fd45d789aa..878bd65662 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -26,7 +26,7 @@ import ( "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm" - "k8s.io/minikube/pkg/minikube/driver" + "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/exit" ) @@ -43,12 +43,13 @@ func init() { } // Bootstrapper returns a new bootstrapper for the cluster -func Bootstrapper(api libmachine.API, bootstrapperName string, cluster string, nodeName string) (bootstrapper.Bootstrapper, error) { +// TODO(#6891): Remove node as an argument +func Bootstrapper(api libmachine.API, bootstrapperName string, cc config.ClusterConfig, n config.Node) (bootstrapper.Bootstrapper, error) { var b bootstrapper.Bootstrapper var err error switch bootstrapperName { case bootstrapper.Kubeadm: - b, err = kubeadm.NewBootstrapper(api, driver.MachineName(cluster, nodeName)) + b, err = kubeadm.NewBootstrapper(api, cc, n) if err != nil { return nil, errors.Wrap(err, "getting a new kubeadm bootstrapper") } diff --git a/pkg/minikube/cluster/iso.go b/pkg/minikube/cluster/iso.go deleted file mode 100644 index 15c06b4a37..0000000000 --- a/pkg/minikube/cluster/iso.go +++ /dev/null @@ -1,30 +0,0 @@ -/* -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 cluster - -import ( - "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/driver" -) - -// CacheISO downloads and caches ISO. -func CacheISO(cfg config.ClusterConfig) error { - if driver.BareMetal(cfg.Driver) { - return nil - } - return cfg.Downloader.CacheMinikubeISOFromURL(cfg.MinikubeISO) -} diff --git a/pkg/minikube/command/ssh_runner.go b/pkg/minikube/command/ssh_runner.go index 66473fd312..9d1f03a04d 100644 --- a/pkg/minikube/command/ssh_runner.go +++ b/pkg/minikube/command/ssh_runner.go @@ -241,11 +241,13 @@ func (s *SSHRunner) sameFileExists(f assets.CopyableFile, dst string) (bool, err if err != nil { return false, err } + glog.Infof("found %s: %d bytes, modified at %s", dst, dstSize, dstModTime) // compare sizes and modtimes if srcSize != dstSize { return false, errors.New("source file and destination file are different sizes") } + return srcModTime.Equal(dstModTime), nil } diff --git a/pkg/minikube/config/config.go b/pkg/minikube/config/config.go index bf7e0bdd28..f11816070c 100644 --- a/pkg/minikube/config/config.go +++ b/pkg/minikube/config/config.go @@ -41,8 +41,8 @@ const ( WantKubectlDownloadMsg = "WantKubectlDownloadMsg" // WantNoneDriverWarning is the key for WantNoneDriverWarning WantNoneDriverWarning = "WantNoneDriverWarning" - // MachineProfile is the key for MachineProfile - MachineProfile = "profile" + // ProfileName represents the key for the global profile parameter + ProfileName = "profile" // ShowDriverDeprecationNotification is the key for ShowDriverDeprecationNotification ShowDriverDeprecationNotification = "ShowDriverDeprecationNotification" // ShowBootstrapperDeprecationNotification is the key for ShowBootstrapperDeprecationNotification diff --git a/pkg/minikube/config/config_test.go b/pkg/minikube/config/config_test.go index 19671ef617..028d094443 100644 --- a/pkg/minikube/config/config_test.go +++ b/pkg/minikube/config/config_test.go @@ -18,6 +18,7 @@ package config import ( "bytes" + "fmt" "io/ioutil" "os" "reflect" @@ -43,13 +44,13 @@ var configTestCases = []configTestCase{ "ReminderWaitPeriodInHours": 99, "cpus": 4, "disk-size": "20g", + "driver": "test-driver", "log_dir": "/etc/hosts", "show-libmachine-logs": true, - "v": 5, - "vm-driver": "test-driver" + "v": 5 }`, config: map[string]interface{}{ - "vm-driver": "test-driver", + "driver": "test-driver", "cpus": 4, "disk-size": "20g", "v": 5, @@ -130,7 +131,7 @@ func TestReadConfig(t *testing.T) { } expectedConfig := map[string]interface{}{ - "vm-driver": "test-driver", + "driver": "test-driver", "cpus": 4, "disk-size": "20g", "show-libmachine-logs": true, @@ -149,7 +150,7 @@ func TestWriteConfig(t *testing.T) { } cfg := map[string]interface{}{ - "vm-driver": "test-driver", + "driver": "test-driver", "cpus": 4, "disk-size": "20g", "show-libmachine-logs": true, @@ -179,6 +180,8 @@ func TestEncode(t *testing.T) { if err != nil { t.Errorf("Error encoding: %v", err) } + fmt.Printf("%+v\n", b.String()) + fmt.Printf("%+v\n", tt.data) if b.String() != tt.data { t.Errorf("Did not write config correctly, \n\n expected:\n %+v \n\n actual:\n %+v", tt.data, b.String()) } diff --git a/pkg/minikube/config/profile.go b/pkg/minikube/config/profile.go index 78dee9a57e..58b8dd1f22 100644 --- a/pkg/minikube/config/profile.go +++ b/pkg/minikube/config/profile.go @@ -105,7 +105,7 @@ func SaveNode(cfg *ClusterConfig, node *Node) error { if !update { cfg.Nodes = append(cfg.Nodes, *node) } - return SaveProfile(viper.GetString(MachineProfile), cfg) + return SaveProfile(viper.GetString(ProfileName), cfg) } // SaveProfile creates an profile out of the cfg and stores in $MINIKUBE_HOME/profiles//config.json diff --git a/pkg/minikube/config/testdata/.minikube/config/valid_config.json b/pkg/minikube/config/testdata/.minikube/config/valid_config.json index 1ddbb4892a..45f6bd608d 100644 --- a/pkg/minikube/config/testdata/.minikube/config/valid_config.json +++ b/pkg/minikube/config/testdata/.minikube/config/valid_config.json @@ -1,5 +1,5 @@ { - "vm-driver": "kvm2", + "driver": "kvm2", "cpus": 4, "disk-size": "20g", "show-libmachine-logs": true, diff --git a/pkg/minikube/config/types.go b/pkg/minikube/config/types.go index 868ad8842e..d58bc92485 100644 --- a/pkg/minikube/config/types.go +++ b/pkg/minikube/config/types.go @@ -20,7 +20,6 @@ import ( "net" "github.com/blang/semver" - "k8s.io/minikube/pkg/util" ) // Profile represents a minikube profile @@ -49,13 +48,12 @@ type ClusterConfig struct { HypervVirtualSwitch string HypervUseExternalSwitch bool HypervExternalAdapter string - KVMNetwork string // Only used by the KVM driver - KVMQemuURI string // Only used by kvm2 - KVMGPU bool // Only used by kvm2 - KVMHidden bool // Only used by kvm2 - Downloader util.ISODownloader `json:"-"` - DockerOpt []string // Each entry is formatted as KEY=VALUE. - DisableDriverMounts bool // Only used by virtualbox + KVMNetwork string // Only used by the KVM driver + KVMQemuURI string // Only used by kvm2 + KVMGPU bool // Only used by kvm2 + KVMHidden bool // Only used by kvm2 + DockerOpt []string // Each entry is formatted as KEY=VALUE. + DisableDriverMounts bool // Only used by virtualbox NFSShare []string NFSSharesRoot string UUID string // Only used by hyperkit to restore the mac address diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index 96495d083e..0f6af77d31 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -17,13 +17,11 @@ limitations under the License. package constants import ( - "fmt" "path/filepath" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" "k8s.io/minikube/pkg/minikube/localpath" - minikubeVersion "k8s.io/minikube/pkg/version" ) const ( @@ -33,11 +31,8 @@ const ( NewestKubernetesVersion = "v1.17.3" // OldestKubernetesVersion is the oldest Kubernetes version to test against OldestKubernetesVersion = "v1.11.10" - // DefaultMachineName is the default name for the VM - DefaultMachineName = "minikube" - // DefaultNodeName is the default name for the kubeadm node within the VM - DefaultNodeName = "minikube" - + // DefaultClusterName is the default nane for the k8s cluster + DefaultClusterName = "minikube" // DockerDaemonPort is the port Docker daemon listening inside a minikube node (vm or container). DockerDaemonPort = 2376 // APIServerPort is the default API server port @@ -75,10 +70,6 @@ var ( // SHASuffix is the suffix of a SHA-256 checksum file SHASuffix = ".sha256" - // DefaultISOURL is the default location of the minikube.iso file - DefaultISOURL = fmt.Sprintf("https://storage.googleapis.com/%s/minikube-%s.iso", minikubeVersion.GetISOPath(), minikubeVersion.GetISOVersion()) - // DefaultISOSHAURL is the default location of the minikube.iso.sha256 file - DefaultISOSHAURL = DefaultISOURL + SHASuffix // DockerDaemonEnvs is list of docker-daemon related environment variables. DockerDaemonEnvs = [3]string{DockerHostEnv, DockerTLSVerifyEnv, DockerCertPathEnv} diff --git a/pkg/minikube/download/binary.go b/pkg/minikube/download/binary.go new file mode 100644 index 0000000000..0eae5600cd --- /dev/null +++ b/pkg/minikube/download/binary.go @@ -0,0 +1,83 @@ +/* +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 download + +import ( + "fmt" + "os" + "path" + "runtime" + + "github.com/blang/semver" + "github.com/golang/glog" + "github.com/hashicorp/go-getter" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/localpath" +) + +// binaryWithChecksumURL gets the location of a Kubernetes binary +func binaryWithChecksumURL(binaryName, version, osName, archName string) (string, error) { + base := fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) + v, err := semver.Make(version[1:]) + if err != nil { + return "", err + } + + if v.GTE(semver.MustParse("1.17.0")) { + return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base), nil + } + return fmt.Sprintf("%s?checksum=file:%s.sha1", base, base), nil +} + +// Binary will download a binary onto the host +func Binary(binary, version, osName, archName string) (string, error) { + targetDir := localpath.MakeMiniPath("cache", osName, version) + targetFilepath := path.Join(targetDir, binary) + + url, err := binaryWithChecksumURL(binary, version, osName, archName) + if err != nil { + return "", err + } + + if _, err := os.Stat(targetFilepath); err == nil { + glog.Infof("Not caching binary, using %s", url) + return targetFilepath, nil + } + + if err = os.MkdirAll(targetDir, 0777); err != nil { + return "", errors.Wrapf(err, "mkdir %s", targetDir) + } + + client := &getter.Client{ + Src: url, + Dst: targetFilepath, + Mode: getter.ClientModeFile, + Options: []getter.ClientOption{getter.WithProgress(DefaultProgressBar)}, + } + + glog.Infof("Downloading: %+v", client) + if err := client.Get(); err != nil { + return "", errors.Wrapf(err, "download failed: %s", url) + } + + if osName == runtime.GOOS && archName == runtime.GOARCH { + if err = os.Chmod(targetFilepath, 0755); err != nil { + return "", errors.Wrapf(err, "chmod +x %s", targetFilepath) + } + } + return targetFilepath, nil +} diff --git a/pkg/minikube/download/binary_test.go b/pkg/minikube/download/binary_test.go new file mode 100644 index 0000000000..79c23131c2 --- /dev/null +++ b/pkg/minikube/download/binary_test.go @@ -0,0 +1,117 @@ +/* +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 download + +import ( + "io/ioutil" + "os" + "runtime" + "testing" +) + +func TestCacheBinary(t *testing.T) { + oldMinikubeHome := os.Getenv("MINIKUBE_HOME") + defer os.Setenv("MINIKUBE_HOME", oldMinikubeHome) + + minikubeHome, err := ioutil.TempDir("/tmp", "") + if err != nil { + t.Fatalf("error during creating tmp dir: %v", err) + } + defer os.RemoveAll(minikubeHome) + noWritePermDir, err := ioutil.TempDir("/tmp", "") + if err != nil { + t.Fatalf("error during creating tmp dir: %v", err) + } + defer os.RemoveAll(noWritePermDir) + err = os.Chmod(noWritePermDir, 0000) + if err != nil { + t.Fatalf("error (%v) during changing permissions of dir %v", err, noWritePermDir) + } + + var tc = []struct { + desc, version, osName, archName string + minikubeHome, binary, description string + err bool + }{ + { + desc: "ok kubeadm", + version: "v1.16.0", + osName: "linux", + archName: runtime.GOARCH, + binary: "kubeadm", + err: false, + minikubeHome: minikubeHome, + }, + { + desc: "minikube home in dir without perms and arm runtime", + version: "v1.16.0", + osName: runtime.GOOS, + archName: "arm", + binary: "kubectl", + err: true, + minikubeHome: noWritePermDir, + }, + { + desc: "minikube home in dir without perms", + version: "v1.16.0", + osName: runtime.GOOS, + archName: runtime.GOARCH, + binary: "kubectl", + err: true, + minikubeHome: noWritePermDir, + }, + { + desc: "binary foo", + version: "v1.16.0", + osName: runtime.GOOS, + archName: runtime.GOARCH, + binary: "foo", + err: true, + minikubeHome: minikubeHome, + }, + { + desc: "version 9000", + version: "v9000", + osName: runtime.GOOS, + archName: runtime.GOARCH, + binary: "foo", + err: true, + minikubeHome: minikubeHome, + }, + { + desc: "bad os", + version: "v1.16.0", + osName: "no-such-os", + archName: runtime.GOARCH, + binary: "kubectl", + err: true, + minikubeHome: minikubeHome, + }, + } + for _, test := range tc { + t.Run(test.desc, func(t *testing.T) { + os.Setenv("MINIKUBE_HOME", test.minikubeHome) + _, err := Binary(test.binary, test.version, test.osName, test.archName) + if err != nil && !test.err { + t.Fatalf("Got unexpected error %v", err) + } + if err == nil && test.err { + t.Fatalf("Expected error but got %v", err) + } + }) + } +} diff --git a/pkg/minikube/download/driver.go b/pkg/minikube/download/driver.go new file mode 100644 index 0000000000..b167987ae7 --- /dev/null +++ b/pkg/minikube/download/driver.go @@ -0,0 +1,53 @@ +/* +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 download + +import ( + "fmt" + "os" + + "github.com/blang/semver" + "github.com/golang/glog" + "github.com/hashicorp/go-getter" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/out" +) + +func driverWithChecksumURL(name string, v semver.Version) string { + base := fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/v%s/%s", v, name) + return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base) +} + +// Driver downloads an arbitrary driver +func Driver(name string, destination string, v semver.Version) error { + out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": name}) + os.Remove(destination) + url := driverWithChecksumURL(name, v) + client := &getter.Client{ + Src: url, + Dst: destination, + Mode: getter.ClientModeFile, + Options: []getter.ClientOption{getter.WithProgress(DefaultProgressBar)}, + } + + glog.Infof("Downloading: %+v", client) + if err := client.Get(); err != nil { + return errors.Wrapf(err, "download failed: %s", url) + } + // Give downloaded drivers a baseline decent file permission + return os.Chmod(destination, 0755) +} diff --git a/pkg/minikube/download/iso.go b/pkg/minikube/download/iso.go new file mode 100644 index 0000000000..bc3e16077d --- /dev/null +++ b/pkg/minikube/download/iso.go @@ -0,0 +1,149 @@ +/* +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 download + +import ( + "fmt" + "net/url" + "os" + "path" + "path/filepath" + "strings" + "time" + + "github.com/golang/glog" + "github.com/hashicorp/go-getter" + "github.com/juju/mutex" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/localpath" + "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/util/lock" + "k8s.io/minikube/pkg/version" +) + +const fileScheme = "file" + +// DefaultISOURLs returns a list of ISO URL's to consult by default, in priority order +func DefaultISOURLs() []string { + v := version.GetISOVersion() + return []string{ + fmt.Sprintf("https://storage.googleapis.com/minikube/iso/minikube-%s.iso", v), + fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/%s/minikube-%s.iso", v, v), + fmt.Sprintf("https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-%s.iso", v), + } +} + +// LocalISOResource returns a local file:// URI equivalent for a local or remote ISO path +func LocalISOResource(isoURL string) string { + u, err := url.Parse(isoURL) + if err != nil { + fake := "file://" + filepath.ToSlash(isoURL) + glog.Errorf("%s is not a URL! Returning %s", isoURL, fake) + return fake + } + + if u.Scheme == fileScheme { + return isoURL + } + + return fileURI(localISOPath(u)) +} + +// fileURI returns a file:// URI for a path +func fileURI(path string) string { + return "file://" + filepath.ToSlash(path) +} + +// localISOPath returns where an ISO should be stored locally +func localISOPath(u *url.URL) string { + if u.Scheme == fileScheme { + return u.String() + } + + return filepath.Join(localpath.MiniPath(), "cache", "iso", path.Base(u.Path)) +} + +// ISO downloads and returns the path to the downloaded ISO +func ISO(urls []string) (string, error) { + out.T(out.ISODownload, "Downloading VM boot image ...") + errs := map[string]string{} + + for _, url := range urls { + err := downloadISO(url) + if err != nil { + glog.Errorf("Unable to download %s: %v", url, err) + errs[url] = err.Error() + continue + } + return url, nil + } + + var msg strings.Builder + msg.WriteString("unable to cache ISO: \n") + for u, err := range errs { + msg.WriteString(fmt.Sprintf(" %s: %s\n", u, err)) + } + + return "", fmt.Errorf(msg.String()) +} + +// downloadISO downloads an ISO URL +func downloadISO(isoURL string) error { + u, err := url.Parse(isoURL) + if err != nil { + return errors.Wrapf(err, "url.parse %q", isoURL) + } + + // It's already downloaded + if u.Scheme == fileScheme { + return nil + } + + // Lock before we check for existence to avoid thundering herd issues + dst := localISOPath(u) + spec := lock.PathMutexSpec(dst) + spec.Timeout = 10 * time.Minute + glog.Infof("acquiring lock: %+v", spec) + releaser, err := mutex.Acquire(spec) + if err != nil { + return errors.Wrapf(err, "unable to acquire lock for %+v", spec) + } + defer releaser.Release() + + if _, err := os.Stat(dst); err == nil { + return nil + } + + urlWithChecksum := isoURL + "?checksum=file:" + isoURL + ".sha256" + + // Predictable temp destination so that resume can function + tmpDst := dst + ".download" + + opts := []getter.ClientOption{getter.WithProgress(DefaultProgressBar)} + client := &getter.Client{ + Src: urlWithChecksum, + Dst: tmpDst, + Mode: getter.ClientModeFile, + Options: opts, + } + + glog.Infof("full url: %s", urlWithChecksum) + if err := client.Get(); err != nil { + return errors.Wrap(err, isoURL) + } + return os.Rename(tmpDst, dst) +} diff --git a/pkg/minikube/download/preload.go b/pkg/minikube/download/preload.go new file mode 100644 index 0000000000..05c0b4c490 --- /dev/null +++ b/pkg/minikube/download/preload.go @@ -0,0 +1,185 @@ +/* +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 download + +import ( + "context" + "crypto/md5" + "fmt" + "io/ioutil" + "net/http" + "os" + "path" + + "cloud.google.com/go/storage" + "google.golang.org/api/option" + + "github.com/golang/glog" + "github.com/hashicorp/go-getter" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/localpath" + "k8s.io/minikube/pkg/minikube/out" +) + +const ( + // PreloadVersion is the current version of the preloaded tarball + PreloadVersion = "v1" + // PreloadBucket is the name of the GCS bucket where preloaded volume tarballs exist + PreloadBucket = "minikube-preloaded-volume-tarballs" +) + +// returns name of the tarball +func tarballName(k8sVersion string) string { + return fmt.Sprintf("preloaded-images-k8s-%s-%s-docker-overlay2.tar.lz4", PreloadVersion, k8sVersion) +} + +// returns the name of the checksum file +func checksumName(k8sVersion string) string { + return fmt.Sprintf("%s.checksum", tarballName(k8sVersion)) +} + +// returns target dir for all cached items related to preloading +func targetDir() string { + return localpath.MakeMiniPath("cache", "preloaded-tarball") +} + +// PreloadChecksumPath returns path to checksum file +func PreloadChecksumPath(k8sVersion string) string { + return path.Join(targetDir(), checksumName(k8sVersion)) +} + +// TarballPath returns the path to the preloaded tarball +func TarballPath(k8sVersion string) string { + return path.Join(targetDir(), tarballName(k8sVersion)) +} + +// remoteTarballURL returns the URL for the remote tarball in GCS +func remoteTarballURL(k8sVersion string) string { + return fmt.Sprintf("https://storage.googleapis.com/%s/%s", PreloadBucket, tarballName(k8sVersion)) +} + +// PreloadExists returns true if there is a preloaded tarball that can be used +func PreloadExists(k8sVersion, containerRuntime string) bool { + if containerRuntime != "docker" { + return false + } + + // Omit remote check if tarball exists locally + targetPath := TarballPath(k8sVersion) + if _, err := os.Stat(targetPath); err == nil { + if err := verifyChecksum(k8sVersion); err == nil { + glog.Infof("Found %s in cache, no need to check remotely", targetPath) + return true + } + } + + url := remoteTarballURL(k8sVersion) + resp, err := http.Head(url) + if err != nil { + glog.Warningf("%s fetch error: %v", url, err) + return false + } + + // note: err won't be set if it's a 404 + if resp.StatusCode != 200 { + glog.Warningf("%s status code: %d", url, resp.StatusCode) + return false + } + + glog.Infof("Goody! %s exists!", url) + return true +} + +// Preload caches the preloaded images tarball on the host machine +func Preload(k8sVersion, containerRuntime string) error { + if containerRuntime != "docker" { + return nil + } + targetPath := TarballPath(k8sVersion) + + if _, err := os.Stat(targetPath); err == nil { + if err := verifyChecksum(k8sVersion); err == nil { + glog.Infof("Found %s in cache, skipping downloading", targetPath) + return nil + } + } + + // Make sure we support this k8s version + if !PreloadExists(k8sVersion, containerRuntime) { + glog.Infof("Preloaded tarball for k8s version %s does not exist", k8sVersion) + return nil + } + + out.T(out.FileDownload, "Downloading preloaded images tarball for k8s {{.version}} ...", out.V{"version": k8sVersion}) + url := remoteTarballURL(k8sVersion) + client := &getter.Client{ + Src: url, + Dst: targetPath, + Mode: getter.ClientModeFile, + Options: []getter.ClientOption{getter.WithProgress(DefaultProgressBar)}, + } + + glog.Infof("Downloading: %+v", client) + if err := client.Get(); err != nil { + return errors.Wrapf(err, "download failed: %s", url) + } + // Give downloaded drivers a baseline decent file permission + if err := os.Chmod(targetPath, 0755); err != nil { + return err + } + // Save checksum file locally + if err := saveChecksumFile(k8sVersion); err != nil { + return errors.Wrap(err, "saving checksum file") + } + return verifyChecksum(k8sVersion) +} + +func saveChecksumFile(k8sVersion string) error { + ctx := context.Background() + client, err := storage.NewClient(ctx, option.WithoutAuthentication()) + if err != nil { + return errors.Wrap(err, "getting storage client") + } + attrs, err := client.Bucket(PreloadBucket).Object(tarballName(k8sVersion)).Attrs(ctx) + if err != nil { + return errors.Wrap(err, "getting storage object") + } + checksum := attrs.MD5 + return ioutil.WriteFile(PreloadChecksumPath(k8sVersion), checksum, 0644) +} + +// verifyChecksum returns true if the checksum of the local binary matches +// the checksum of the remote binary +func verifyChecksum(k8sVersion string) error { + // get md5 checksum of tarball path + contents, err := ioutil.ReadFile(TarballPath(k8sVersion)) + if err != nil { + return errors.Wrap(err, "reading tarball") + } + checksum := md5.Sum(contents) + + remoteChecksum, err := ioutil.ReadFile(PreloadChecksumPath(k8sVersion)) + if err != nil { + return errors.Wrap(err, "reading checksum file") + } + + // create a slice of checksum, which is [16]byte + if string(remoteChecksum) != string(checksum[:]) { + return fmt.Errorf("checksum of %s does not match remote checksum (%s != %s)", TarballPath(k8sVersion), string(remoteChecksum), string(checksum[:])) + } + return nil +} diff --git a/pkg/util/progressbar.go b/pkg/minikube/download/progressbar.go similarity index 99% rename from pkg/util/progressbar.go rename to pkg/minikube/download/progressbar.go index fb16f6773c..6995855b68 100644 --- a/pkg/util/progressbar.go +++ b/pkg/minikube/download/progressbar.go @@ -18,7 +18,7 @@ limitations under the License. // based on: // https://github.com/hashicorp/go-getter/blob/master/cmd/go-getter/progress_tracking.go -package util +package download import ( "io" diff --git a/pkg/minikube/driver/driver.go b/pkg/minikube/driver/driver.go index 21ebc7c432..2dce6350cd 100644 --- a/pkg/minikube/driver/driver.go +++ b/pkg/minikube/driver/driver.go @@ -24,6 +24,7 @@ import ( "github.com/golang/glog" "k8s.io/minikube/pkg/drivers/kic" + "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/registry" ) @@ -85,7 +86,21 @@ func Supported(name string) bool { return false } -// IsKIC checks if the driver is a kubernetes in continer +// MachineType returns appropriate machine name for the driver +func MachineType(name string) string { + if IsKIC(name) { + return "container" + } + + if IsVM(name) { + return "VM" + } + + // none or mock + return "bare metal machine" +} + +// IsKIC checks if the driver is a kubernetes in container func IsKIC(name string) bool { return name == Docker || name == Podman } @@ -108,11 +123,6 @@ func BareMetal(name string) bool { return name == None || name == Mock } -// MachineName return the name of the machine given proper config -func MachineName(cluster string, node string) string { - return fmt.Sprintf("%s-%s", cluster, node) -} - // NeedsRoot returns true if driver needs to run with root privileges func NeedsRoot(name string) bool { return name == None || name == Podman @@ -217,3 +227,12 @@ func SetLibvirtURI(v string) { os.Setenv("LIBVIRT_DEFAULT_URI", v) } + +// MachineName returns the name of the machine, as seen by the hypervisor given the cluster and node names +func MachineName(cc config.ClusterConfig, n config.Node) string { + // For single node cluster, default to back to old naming + if len(cc.Nodes) == 1 || n.ControlPlane { + return cc.Name + } + return fmt.Sprintf("%s-%s", cc.Name, n.Name) +} diff --git a/pkg/minikube/driver/driver_test.go b/pkg/minikube/driver/driver_test.go index f34f936ad6..8f9be829ad 100644 --- a/pkg/minikube/driver/driver_test.go +++ b/pkg/minikube/driver/driver_test.go @@ -58,6 +58,31 @@ func TestBareMetal(t *testing.T) { } } +func TestMachineType(t *testing.T) { + types := map[string]string{ + Podman: "container", + Docker: "container", + Mock: "bare metal machine", + None: "bare metal machine", + KVM2: "VM", + VirtualBox: "VM", + HyperKit: "VM", + VMware: "VM", + VMwareFusion: "VM", + HyperV: "VM", + Parallels: "VM", + } + + drivers := SupportedDrivers() + for _, driver := range drivers { + want := types[driver] + got := MachineType(driver) + if want != got { + t.Errorf("mismatched machine type for driver %s: want = %s got = %s", driver, want, got) + } + } +} + func TestFlagDefaults(t *testing.T) { expected := FlagHints{CacheImages: true} if diff := cmp.Diff(FlagDefaults(VirtualBox), expected); diff != "" { diff --git a/pkg/minikube/driver/install.go b/pkg/minikube/driver/install.go index 8a49e833fa..ae17a917cd 100644 --- a/pkg/minikube/driver/install.go +++ b/pkg/minikube/driver/install.go @@ -27,12 +27,11 @@ import ( "github.com/blang/semver" "github.com/golang/glog" - "github.com/hashicorp/go-getter" "github.com/juju/mutex" "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/out" - "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/util/lock" ) @@ -59,7 +58,7 @@ func InstallOrUpdate(name string, directory string, v semver.Version, interactiv if !exists || (err != nil && autoUpdate) { glog.Warningf("%s: %v", executable, err) path = filepath.Join(directory, executable) - derr := download(executable, path, v) + derr := download.Driver(executable, path, v) if derr != nil { return derr } @@ -139,31 +138,6 @@ func validateDriver(executable string, v semver.Version) (string, error) { return path, nil } -func driverWithChecksumURL(name string, v semver.Version) string { - base := fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/v%s/%s", v, name) - return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base) -} - -// download an arbitrary driver -func download(name string, destination string, v semver.Version) error { - out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": name}) - os.Remove(destination) - url := driverWithChecksumURL(name, v) - client := &getter.Client{ - Src: url, - Dst: destination, - Mode: getter.ClientModeFile, - Options: []getter.ClientOption{getter.WithProgress(util.DefaultProgressBar)}, - } - - glog.Infof("Downloading: %+v", client) - if err := client.Get(); err != nil { - return errors.Wrapf(err, "download failed: %s", url) - } - // Give downloaded drivers a baseline decent file permission - return os.Chmod(destination, 0755) -} - // extractDriverVersion extracts the driver version. // KVM and Hyperkit drivers support the 'version' command, that display the information as: // version: vX.X.X diff --git a/pkg/minikube/image/image.go b/pkg/minikube/image/image.go index 5a61f840e4..a14ad85f71 100644 --- a/pkg/minikube/image/image.go +++ b/pkg/minikube/image/image.go @@ -20,7 +20,10 @@ import ( "context" "io/ioutil" "os" + "os/exec" "path/filepath" + "runtime" + "strings" "time" "github.com/docker/docker/client" @@ -30,14 +33,22 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/daemon" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/drivers/kic/oci" "k8s.io/minikube/pkg/minikube/constants" ) +var defaultPlatform = v1.Platform{ + Architecture: runtime.GOARCH, + OS: "linux", +} + // DigestByDockerLib uses client by docker lib to return image digest // img.ID in as same as image digest func DigestByDockerLib(imgClient *client.Client, imgName string) string { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() + imgClient.NegotiateAPIVersion(ctx) img, _, err := imgClient.ImageInspectWithRaw(ctx, imgName) if err != nil && !client.IsErrNotFound(err) { glog.Infof("couldn't find image digest %s from local daemon: %v ", imgName, err) @@ -69,6 +80,37 @@ func DigestByGoLib(imgName string) string { return cf.Hex } +// WriteImageToDaemon write img to the local docker daemon +func WriteImageToDaemon(img string) error { + glog.Infof("Writing %s to local daemon", img) + if err := oci.PointToHostDockerDaemon(); err != nil { + return errors.Wrap(err, "point host docker-daemon") + } + // Check if image exists locally + cmd := exec.Command("docker", "images", "--format", "{{.Repository}}:{{.Tag}}@{{.Digest}}") + if output, err := cmd.Output(); err == nil { + if strings.Contains(string(output), img) { + glog.Infof("Found %s in local docker daemon, skipping pull", img) + return nil + } + } + // Else, pull it + ref, err := name.ParseReference(img) + if err != nil { + return errors.Wrap(err, "parsing reference") + } + i, err := remote.Image(ref) + if err != nil { + return errors.Wrap(err, "getting remote image") + } + tag, err := name.NewTag(strings.Split(img, "@")[0]) + if err != nil { + return errors.Wrap(err, "getting tag") + } + _, err = daemon.Write(tag, i) + return err +} + func retrieveImage(ref name.Reference) (v1.Image, error) { glog.Infof("retrieving image: %+v", ref) img, err := daemon.Image(ref) @@ -81,7 +123,8 @@ func retrieveImage(ref name.Reference) (v1.Image, error) { glog.Infof("daemon lookup for %+v: %v", ref, err) } - img, err = remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain)) + platform := defaultPlatform + img, err = remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain), remote.WithPlatform(platform)) if err == nil { return img, nil } diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index 898540eab3..3bb9d4d998 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -17,22 +17,15 @@ limitations under the License. package machine import ( - "crypto" - "fmt" - "os" "path" "runtime" - "github.com/blang/semver" - "github.com/golang/glog" - "github.com/jimmidyson/go-download" "github.com/pkg/errors" "golang.org/x/sync/errgroup" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" - "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/minikube/download" ) // CacheBinariesForBootstrapper will cache binaries for a bootstrapper @@ -43,7 +36,7 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er for _, bin := range binaries { bin := bin // https://golang.org/doc/faq#closures_and_goroutines g.Go(func() error { - if _, err := CacheBinary(bin, version, "linux", runtime.GOARCH); err != nil { + if _, err := download.Binary(bin, version, "linux", runtime.GOARCH); err != nil { return errors.Wrapf(err, "caching binary %s", bin) } return nil @@ -52,73 +45,6 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er return g.Wait() } -// releaseURL gets the location of a Kubernetes binary -func releaseURL(binaryName, version, osName, archName string) string { - return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) -} - -// downloadOptions returns appropriate download options for a -func downloadOptions(url string, version string) (download.FileOptions, error) { - fo := download.FileOptions{ - Mkdirs: download.MkdirAll, - Options: download.Options{ - ChecksumHash: crypto.SHA1, - Checksum: url + ".sha1", - }, - } - - v, err := semver.Make(version[1:]) - if err != nil { - return fo, err - } - - if v.GTE(semver.MustParse("1.17.0")) { - fo.ChecksumHash = crypto.SHA256 - fo.Checksum = url + ".sha256" - } - return fo, nil -} - -// CacheBinary will cache a binary on the host -func CacheBinary(binary, version, osName, archName string) (string, error) { - - targetDir := localpath.MakeMiniPath("cache", osName, version) - targetFilepath := path.Join(targetDir, binary) - - url := releaseURL(binary, version, osName, archName) - - _, err := os.Stat(targetFilepath) - // If it exists, do no verification and continue - if err == nil { - glog.Infof("Not caching binary, using %s", url) - return targetFilepath, nil - } - if !os.IsNotExist(err) { - return "", errors.Wrapf(err, "stat %s version %s at %s", binary, version, targetDir) - } - - if err = os.MkdirAll(targetDir, 0777); err != nil { - return "", errors.Wrapf(err, "mkdir %s", targetDir) - } - - options, err := downloadOptions(url, version) - if err != nil { - return "", errors.Wrap(err, "options") - } - glog.Infof("Downloading %s: options: %+v", url, options) - - out.T(out.FileDownload, "Downloading {{.name}} {{.version}}", out.V{"name": binary, "version": version}) - if err := download.ToFile(url, targetFilepath, options); err != nil { - return "", errors.Wrapf(err, url) - } - if osName == runtime.GOOS && archName == runtime.GOARCH { - if err = os.Chmod(targetFilepath, 0755); err != nil { - return "", errors.Wrapf(err, "chmod +x %s", targetFilepath) - } - } - return targetFilepath, nil -} - // CopyBinary copies a locally cached binary to the guest VM func CopyBinary(cr command.Runner, src string, dest string) error { f, err := assets.NewFileAsset(src, path.Dir(dest), path.Base(dest), "0755") diff --git a/pkg/minikube/machine/cache_binaries_test.go b/pkg/minikube/machine/cache_binaries_test.go index b490974eac..500c0ea74d 100644 --- a/pkg/minikube/machine/cache_binaries_test.go +++ b/pkg/minikube/machine/cache_binaries_test.go @@ -17,15 +17,11 @@ limitations under the License. package machine import ( - "crypto" "fmt" "io/ioutil" "os" - "runtime" "testing" - "github.com/google/go-cmp/cmp" - "github.com/jimmidyson/go-download" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" @@ -126,149 +122,3 @@ func TestCacheBinariesForBootstrapper(t *testing.T) { }) } } -func TestCacheBinary(t *testing.T) { - oldMinikubeHome := os.Getenv("MINIKUBE_HOME") - defer os.Setenv("MINIKUBE_HOME", oldMinikubeHome) - - minikubeHome, err := ioutil.TempDir("/tmp", "") - if err != nil { - t.Fatalf("error during creating tmp dir: %v", err) - } - defer os.RemoveAll(minikubeHome) - noWritePermDir, err := ioutil.TempDir("/tmp", "") - if err != nil { - t.Fatalf("error during creating tmp dir: %v", err) - } - defer os.RemoveAll(noWritePermDir) - err = os.Chmod(noWritePermDir, 0000) - if err != nil { - t.Fatalf("error (%v) during changing permissions of dir %v", err, noWritePermDir) - } - - var tc = []struct { - desc, version, osName, archName string - minikubeHome, binary, description string - err bool - }{ - { - desc: "ok kubeadm", - version: "v1.16.0", - osName: "linux", - archName: runtime.GOARCH, - binary: "kubeadm", - err: false, - minikubeHome: minikubeHome, - }, - { - desc: "minikube home in dir without perms and arm runtime", - version: "v1.16.0", - osName: runtime.GOOS, - archName: "arm", - binary: "kubectl", - err: true, - minikubeHome: noWritePermDir, - }, - { - desc: "minikube home in dir without perms", - version: "v1.16.0", - osName: runtime.GOOS, - archName: runtime.GOARCH, - binary: "kubectl", - err: true, - minikubeHome: noWritePermDir, - }, - { - desc: "binary foo", - version: "v1.16.0", - osName: runtime.GOOS, - archName: runtime.GOARCH, - binary: "foo", - err: true, - minikubeHome: minikubeHome, - }, - { - desc: "version 9000", - version: "v9000", - osName: runtime.GOOS, - archName: runtime.GOARCH, - binary: "foo", - err: true, - minikubeHome: minikubeHome, - }, - { - desc: "bad os", - version: "v1.16.0", - osName: "no-such-os", - archName: runtime.GOARCH, - binary: "kubectl", - err: true, - minikubeHome: minikubeHome, - }, - } - for _, test := range tc { - t.Run(test.desc, func(t *testing.T) { - os.Setenv("MINIKUBE_HOME", test.minikubeHome) - _, err := CacheBinary(test.binary, test.version, test.osName, test.archName) - if err != nil && !test.err { - t.Fatalf("Got unexpected error %v", err) - } - if err == nil && test.err { - t.Fatalf("Expected error but got %v", err) - } - }) - } -} - -func TestDownloadOptions(t *testing.T) { - var tc = []struct { - url string - version string - want download.FileOptions - }{ - { - url: "https://s/kubernetes-release/release/v1.16.0/bin/amd64/kubectl", - version: "v1.16.0", - want: download.FileOptions{ - Options: download.Options{ - Checksum: "https://s/kubernetes-release/release/v1.16.0/bin/amd64/kubectl.sha1", - ChecksumHash: crypto.SHA1, - }, - Mkdirs: download.MkdirAll, - }, - }, - { - url: "https://s/kubernetes-release/release/v1.10.0/bin/hp9k/kubeadm", - version: "v1.10.0", - want: download.FileOptions{ - Options: download.Options{ - Checksum: "https://s/kubernetes-release/release/v1.10.0/bin/hp9k/kubeadm.sha1", - ChecksumHash: crypto.SHA1, - }, - Mkdirs: download.MkdirAll, - }, - }, - { - url: "https://s/kubernetes-release/release/v1.18.0/bin/arm64/kubelet", - version: "v1.18.0", - want: download.FileOptions{ - Options: download.Options{ - Checksum: "https://s/kubernetes-release/release/v1.18.0/bin/arm64/kubelet.sha256", - ChecksumHash: crypto.SHA256, - }, - Mkdirs: download.MkdirAll, - }, - }, - } - for _, test := range tc { - t.Run(test.version, func(t *testing.T) { - got, err := downloadOptions(test.url, test.version) - if err != nil { - t.Fatalf("unexpected error %v", err) - } - - if diff := cmp.Diff(test.want, got); diff != "" { - t.Errorf("unexpected options(-want +got):\n%s", diff) - } - }) - } -} diff --git a/pkg/minikube/machine/cache_images.go b/pkg/minikube/machine/cache_images.go index 40e35a2c69..ffa0aa7c18 100644 --- a/pkg/minikube/machine/cache_images.go +++ b/pkg/minikube/machine/cache_images.go @@ -19,8 +19,10 @@ package machine import ( "fmt" "os" + "os/exec" "path" "path/filepath" + "strings" "sync" "time" @@ -35,6 +37,7 @@ import ( "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/image" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/vmpath" @@ -62,6 +65,12 @@ func CacheImagesForBootstrapper(imageRepository string, version string, clusterB // LoadImages loads previously cached images into the container runtime func LoadImages(cc *config.ClusterConfig, runner command.Runner, images []string, cacheDir string) error { + // Skip loading images if images already exist + if imagesPreloaded(runner, images) { + glog.Infof("Images are preloaded, skipping loading") + return nil + } + glog.Infof("LoadImages start: %s", images) start := time.Now() @@ -99,6 +108,28 @@ func LoadImages(cc *config.ClusterConfig, runner command.Runner, images []string return nil } +func imagesPreloaded(runner command.Runner, images []string) bool { + rr, err := runner.RunCmd(exec.Command("docker", "images", "--format", "{{.Repository}}:{{.Tag}}")) + if err != nil { + return false + } + preloadedImages := map[string]struct{}{} + for _, i := range strings.Split(rr.Stdout.String(), "\n") { + preloadedImages[i] = struct{}{} + } + + glog.Infof("Got preloaded images: %s", rr.Output()) + + // Make sure images == imgs + for _, i := range images { + if _, ok := preloadedImages[i]; !ok { + glog.Infof("%s wasn't preloaded", i) + return false + } + } + return true +} + // needsTransfer returns an error if an image needs to be retransfered func needsTransfer(imgClient *client.Client, imgName string, cr cruntime.Manager) error { imgDgst := "" // for instance sha256:7c92a2c6bbcb6b6beff92d0a940779769c2477b807c202954c537e2e0deb9bed @@ -137,16 +168,21 @@ func CacheAndLoadImages(images []string) error { return errors.Wrap(err, "list profiles") } for _, p := range profiles { // loading images to all running profiles - for _, n := range p.Config.Nodes { - pName := n.Name // capture the loop variable - status, err := GetHostStatus(api, pName) + pName := p.Name // capture the loop variable + c, err := config.Load(pName) + if err != nil { + return err + } + for _, n := range c.Nodes { + m := driver.MachineName(*c, n) + status, err := GetHostStatus(api, m) if err != nil { glog.Warningf("skipping loading cache for profile %s", pName) glog.Errorf("error getting status for %s: %v", pName, err) continue // try next machine } if status == state.Running.String() { // the not running hosts will load on next start - h, err := api.Load(pName) + h, err := api.Load(m) if err != nil { return err } @@ -154,10 +190,6 @@ func CacheAndLoadImages(images []string) error { if err != nil { return err } - c, err := config.Load(pName) - if err != nil { - return err - } err = LoadImages(c, cr, images, constants.ImageCacheDir) if err != nil { glog.Warningf("Failed to load cached images for profile %s. make sure the profile is running. %v", pName, err) diff --git a/pkg/minikube/machine/cluster_test.go b/pkg/minikube/machine/cluster_test.go index 2b26215c6c..2f7cd5b15b 100644 --- a/pkg/minikube/machine/cluster_test.go +++ b/pkg/minikube/machine/cluster_test.go @@ -30,17 +30,11 @@ import ( "github.com/docker/machine/libmachine/state" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/registry" "k8s.io/minikube/pkg/minikube/tests" ) -type MockDownloader struct{} - -func (d MockDownloader) GetISOFileURI(isoURL string) string { return "" } -func (d MockDownloader) CacheMinikubeISOFromURL(isoURL string) error { return nil } - func createMockDriverHost(c config.ClusterConfig, n config.Node) (interface{}, error) { return nil, nil } @@ -61,14 +55,10 @@ func RegisterMockDriver(t *testing.T) { } var defaultClusterConfig = config.ClusterConfig{ - Driver: driver.Mock, - MinikubeISO: constants.DefaultISOURL, - Downloader: MockDownloader{}, - DockerEnv: []string{"MOCK_MAKE_IT_PROVISION=true"}, -} - -var defaultNodeConfig = config.Node{ - Name: viper.GetString("profile"), + Name: viper.GetString("profile"), + Driver: driver.Mock, + DockerEnv: []string{"MOCK_MAKE_IT_PROVISION=true"}, + Nodes: []config.Node{config.Node{Name: "minikube"}}, } func TestCreateHost(t *testing.T) { @@ -80,9 +70,7 @@ func TestCreateHost(t *testing.T) { t.Fatal("Machine already exists.") } - n := config.Node{Name: viper.GetString("profile")} - - _, err := createHost(api, defaultClusterConfig, n) + _, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Fatalf("Error creating host: %v", err) } @@ -123,7 +111,7 @@ func TestStartHostExists(t *testing.T) { n := defaultNodeConfig // Create an initial host. - ih, err := createHost(api, defaultClusterConfig, defaultNodeConfig) + ih, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Fatalf("Error creating host: %v", err) } @@ -140,7 +128,7 @@ func TestStartHostExists(t *testing.T) { mc := defaultClusterConfig mc.Name = ih.Name - n.Name = ih.Name + n := config.Node{Name: ih.Name} // This should pass without calling Create because the host exists already. h, err := StartHost(api, mc, n) @@ -163,7 +151,7 @@ func TestStartHostErrMachineNotExist(t *testing.T) { api := tests.NewMockAPI(t) // Create an incomplete host with machine does not exist error(i.e. User Interrupt Cancel) api.NotExistError = true - h, err := createHost(api, defaultClusterConfig, defaultNodeConfig) + h, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Fatalf("Error creating host: %v", err) } @@ -185,6 +173,7 @@ func TestStartHostErrMachineNotExist(t *testing.T) { } mc.Name = h.Name + n.Name = h.Name n.Name = h.Name @@ -209,7 +198,7 @@ func TestStartStoppedHost(t *testing.T) { RegisterMockDriver(t) api := tests.NewMockAPI(t) // Create an initial host. - h, err := createHost(api, defaultClusterConfig, defaultNodeConfig) + h, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Fatalf("Error creating host: %v", err) } @@ -221,9 +210,7 @@ func TestStartStoppedHost(t *testing.T) { provision.SetDetector(md) mc := defaultClusterConfig mc.Name = h.Name - n := config.Node{Name: h.Name} - h, err = StartHost(api, mc, n) if err != nil { t.Fatal("Error starting host.") @@ -252,9 +239,7 @@ func TestStartHost(t *testing.T) { md := &tests.MockDetector{Provisioner: &tests.MockProvisioner{}} provision.SetDetector(md) - n := config.Node{Name: viper.GetString("profile")} - - h, err := StartHost(api, defaultClusterConfig, n) + h, err := StartHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Fatal("Error starting host.") } @@ -283,15 +268,12 @@ func TestStartHostConfig(t *testing.T) { provision.SetDetector(md) cfg := config.ClusterConfig{ - Driver: driver.Mock, - DockerEnv: []string{"FOO=BAR"}, - DockerOpt: []string{"param=value"}, - Downloader: MockDownloader{}, + Driver: driver.Mock, + DockerEnv: []string{"FOO=BAR"}, + DockerOpt: []string{"param=value"}, } - n := config.Node{Name: viper.GetString("profile")} - - h, err := StartHost(api, cfg, n) + h, err := StartHost(api, cfg, config.Node{Name: "minikube"}) if err != nil { t.Fatal("Error starting host.") } @@ -321,13 +303,16 @@ func TestStopHostError(t *testing.T) { func TestStopHost(t *testing.T) { RegisterMockDriver(t) api := tests.NewMockAPI(t) - h, err := createHost(api, defaultClusterConfig, defaultNodeConfig) + h, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Errorf("createHost failed: %v", err) } - if err := StopHost(api, viper.GetString("profile")); err != nil { - t.Fatal("An error should be thrown when stopping non-existing machine.") + cc := defaultClusterConfig + cc.Name = viper.GetString("profile") + m := driver.MachineName(cc, config.Node{Name: "minikube"}) + if err := StopHost(api, m); err != nil { + t.Fatalf("Unexpected error stopping machine: %v", err) } if s, _ := h.Driver.GetState(); s != state.Stopped { t.Fatalf("Machine not stopped. Currently in state: %s", s) @@ -337,11 +322,14 @@ func TestStopHost(t *testing.T) { func TestDeleteHost(t *testing.T) { RegisterMockDriver(t) api := tests.NewMockAPI(t) - if _, err := createHost(api, defaultClusterConfig, defaultNodeConfig); err != nil { + if _, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}); err != nil { t.Errorf("createHost failed: %v", err) } - if err := DeleteHost(api, viper.GetString("profile")); err != nil { + cc := defaultClusterConfig + cc.Name = viper.GetString("profile") + + if err := DeleteHost(api, driver.MachineName(cc, config.Node{Name: "minikube"})); err != nil { t.Fatalf("Unexpected error deleting host: %v", err) } } @@ -349,7 +337,7 @@ func TestDeleteHost(t *testing.T) { func TestDeleteHostErrorDeletingVM(t *testing.T) { RegisterMockDriver(t) api := tests.NewMockAPI(t) - h, err := createHost(api, defaultClusterConfig, defaultNodeConfig) + h, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Errorf("createHost failed: %v", err) } @@ -357,7 +345,7 @@ func TestDeleteHostErrorDeletingVM(t *testing.T) { d := &tests.MockDriver{RemoveError: true, T: t} h.Driver = d - if err := DeleteHost(api, viper.GetString("profile")); err == nil { + if err := DeleteHost(api, driver.MachineName(defaultClusterConfig, config.Node{Name: "minikube"})); err == nil { t.Fatal("Expected error deleting host.") } } @@ -366,11 +354,11 @@ func TestDeleteHostErrorDeletingFiles(t *testing.T) { RegisterMockDriver(t) api := tests.NewMockAPI(t) api.RemoveError = true - if _, err := createHost(api, defaultClusterConfig, defaultNodeConfig); err != nil { + if _, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}); err != nil { t.Errorf("createHost failed: %v", err) } - if err := DeleteHost(api, viper.GetString("profile")); err == nil { + if err := DeleteHost(api, driver.MachineName(defaultClusterConfig, config.Node{Name: "minikube"})); err == nil { t.Fatal("Expected error deleting host.") } } @@ -380,12 +368,12 @@ func TestDeleteHostErrMachineNotExist(t *testing.T) { api := tests.NewMockAPI(t) // Create an incomplete host with machine does not exist error(i.e. User Interrupt Cancel) api.NotExistError = true - _, err := createHost(api, defaultClusterConfig, defaultNodeConfig) + _, err := createHost(api, defaultClusterConfig, config.Node{Name: "minikube"}) if err != nil { t.Errorf("createHost failed: %v", err) } - if err := DeleteHost(api, viper.GetString("profile")); err == nil { + if err := DeleteHost(api, driver.MachineName(defaultClusterConfig, config.Node{Name: "minikube"})); err == nil { t.Fatal("Expected error deleting host.") } } @@ -394,28 +382,37 @@ func TestGetHostStatus(t *testing.T) { RegisterMockDriver(t) api := tests.NewMockAPI(t) - checkState := func(expected string) { - s, err := GetHostStatus(api, viper.GetString("profile")) + cc := defaultClusterConfig + cc.Name = viper.GetString("profile") + + m := driver.MachineName(cc, config.Node{Name: "minikube"}) + + checkState := func(expected string, machineName string) { + s, err := GetHostStatus(api, machineName) if err != nil { t.Fatalf("Unexpected error getting status: %v", err) } if s != expected { - t.Fatalf("Expected status: %s, got %s", s, expected) + t.Fatalf("Expected status: %s, got: %s", expected, s) } } - checkState(state.None.String()) + checkState(state.None.String(), m) - if _, err := createHost(api, defaultClusterConfig, defaultNodeConfig); err != nil { + if _, err := createHost(api, cc, config.Node{Name: "minikube"}); err != nil { t.Errorf("createHost failed: %v", err) } - checkState(state.Running.String()) + cc.Name = viper.GetString("profile") - if err := StopHost(api, viper.GetString("profile")); err != nil { + m = driver.MachineName(cc, config.Node{Name: "minikube"}) + + checkState(state.Running.String(), m) + + if err := StopHost(api, m); err != nil { t.Errorf("StopHost failed: %v", err) } - checkState(state.Stopped.String()) + checkState(state.Stopped.String(), m) } func TestCreateSSHShell(t *testing.T) { @@ -441,8 +438,11 @@ func TestCreateSSHShell(t *testing.T) { } api.Hosts[m] = &host.Host{Driver: d} + cc := defaultClusterConfig + cc.Name = viper.GetString("profile") + cliArgs := []string{"exit"} - if err := CreateSSHShell(api, m, cliArgs); err != nil { + if err := CreateSSHShell(api, cc, config.Node{Name: "minikube"}, cliArgs); err != nil { t.Fatalf("Error running ssh command: %v", err) } diff --git a/pkg/minikube/machine/delete.go b/pkg/minikube/machine/delete.go index 9a7fa00a81..c18e4c9183 100644 --- a/pkg/minikube/machine/delete.go +++ b/pkg/minikube/machine/delete.go @@ -17,7 +17,9 @@ limitations under the License. package machine import ( + "context" "os/exec" + "time" "github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine/mcnerror" @@ -29,10 +31,30 @@ import ( "k8s.io/minikube/pkg/minikube/out" ) -// deleteOrphanedKIC attempts to delete an orphaned docker instance -func deleteOrphanedKIC(name string) { - cmd := exec.Command(oci.Docker, "rm", "-f", "-v", name) - err := cmd.Run() +// deleteOrphanedKIC attempts to delete an orphaned docker instance for machines without a config file +// used as last effort clean up not returning errors, wont warn user. +func deleteOrphanedKIC(ociBin string, name string) { + if !(ociBin == oci.Podman || ociBin == oci.Docker) { + return + } + if ociBin == oci.Docker { + if err := oci.PointToHostDockerDaemon(); err != nil { + glog.Infof("Failed to point to host docker-damon: %v", err) + return + } + } + + _, err := oci.ContainerStatus(ociBin, name) + if err != nil { + glog.Infof("couldn't inspect container %q before deleting, %s-daemon might needs a restart!: %v", name, ociBin, err) + return + } + // allow no more than 5 seconds for delting the container + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + cmd := exec.CommandContext(ctx, ociBin, "rm", "-f", "-v", name) + err = cmd.Run() if err == nil { glog.Infof("Found stale kic container and successfully cleaned it up!") } @@ -42,7 +64,8 @@ func deleteOrphanedKIC(name string) { func DeleteHost(api libmachine.API, machineName string) error { host, err := api.Load(machineName) if err != nil && host == nil { - deleteOrphanedKIC(machineName) + deleteOrphanedKIC(oci.Docker, machineName) + deleteOrphanedKIC(oci.Podman, machineName) // Keep going even if minikube does not know about the host } diff --git a/pkg/minikube/machine/fix.go b/pkg/minikube/machine/fix.go index 3b465e5025..efcde90ad7 100644 --- a/pkg/minikube/machine/fix.go +++ b/pkg/minikube/machine/fix.go @@ -19,12 +19,12 @@ package machine import ( "fmt" "math" + "os" "strconv" "strings" "time" "github.com/docker/machine/drivers/virtualbox" - "github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/provision" @@ -32,6 +32,7 @@ import ( "github.com/golang/glog" "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/util/retry" @@ -54,7 +55,7 @@ var ( ) // fixHost fixes up a previously configured VM so that it is ready to run Kubernetes -func fixHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host.Host, error) { +func fixHost(api libmachine.API, cc config.ClusterConfig, n config.Node) (*host.Host, error) { out.T(out.Waiting, "Reconfiguring existing host ...") start := time.Now() @@ -63,11 +64,14 @@ func fixHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host. glog.Infof("fixHost completed within %s", time.Since(start)) }() - h, err := api.Load(n.Name) + h, err := api.Load(driver.MachineName(cc, n)) if err != nil { return h, errors.Wrap(err, "Error loading existing host. Please try running [minikube delete], then run [minikube start] again.") } + // check if need to re-run docker-env + maybeWarnAboutEvalEnv(cc.Driver, cc.Name) + s, err := h.Driver.GetState() if err != nil || s == state.Stopped || s == state.None { // If virtual machine does not exist due to user interrupt cancel(i.e. Ctrl + C), recreate virtual machine @@ -83,12 +87,12 @@ func fixHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host. } } // remove machine config directory - if err := api.Remove(mc.Name); err != nil { + if err := api.Remove(cc.Name); err != nil { return nil, errors.Wrap(err, "api remove") } // recreate virtual machine - out.T(out.Meh, "machine '{{.name}}' does not exist. Proceeding ahead with recreating VM.", out.V{"name": mc.Name}) - h, err = createHost(api, mc, n) + out.T(out.Meh, "machine '{{.name}}' does not exist. Proceeding ahead with recreating VM.", out.V{"name": cc.Name}) + h, err = createHost(api, cc, n) if err != nil { return nil, errors.Wrap(err, "Error recreating VM") } @@ -100,10 +104,11 @@ func fixHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host. } } + machineType := driver.MachineType(cc.Driver) if s == state.Running { - out.T(out.Running, `Using the running {{.driver_name}} "{{.profile_name}}" VM ...`, out.V{"driver_name": mc.Driver, "profile_name": mc.Name}) + out.T(out.Running, `Using the running {{.driver_name}} "{{.profile_name}}" {{.machine_type}} ...`, out.V{"driver_name": cc.Driver, "profile_name": cc.Name, "machine_type": machineType}) } else { - out.T(out.Restarting, `Starting existing {{.driver_name}} VM for "{{.profile_name}}" ...`, out.V{"driver_name": mc.Driver, "profile_name": mc.Name}) + out.T(out.Restarting, `Starting existing {{.driver_name}} {{.machine_type}} for "{{.profile_name}}" ...`, out.V{"driver_name": cc.Driver, "profile_name": cc.Name, "machine_type": machineType}) if err := h.Driver.Start(); err != nil { return h, errors.Wrap(err, "driver start") } @@ -112,7 +117,7 @@ func fixHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host. } } - e := engineOptions(mc) + e := engineOptions(cc) if len(e.Env) > 0 { h.HostOptions.EngineOptions.Env = e.Env glog.Infof("Detecting provisioner ...") @@ -129,7 +134,7 @@ func fixHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host. return h, nil } - if err := postStartSetup(h, mc); err != nil { + if err := postStartSetup(h, cc); err != nil { return h, errors.Wrap(err, "post-start") } @@ -142,7 +147,27 @@ func fixHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host. if err := h.ConfigureAuth(); err != nil { return h, &retry.RetriableError{Err: errors.Wrap(err, "Error configuring auth on host")} } - return h, ensureSyncedGuestClock(h, mc.Driver) + return h, ensureSyncedGuestClock(h, cc.Driver) +} + +// maybeWarnAboutEvalEnv wil warn user if they need to re-eval their docker-env, podman-env +// because docker changes the allocated bind ports after restart https://github.com/kubernetes/minikube/issues/6824 +func maybeWarnAboutEvalEnv(drver string, name string) { + if !driver.IsKIC(drver) { + return + } + p := os.Getenv(constants.MinikubeActiveDockerdEnv) + if p == "" { + return + } + out.T(out.Notice, "Noticed that you are using minikube docker-env:") + out.T(out.WarningType, `After minikube restart the dockerd ports might have changed. To ensure docker-env works properly. +Please re-eval the docker-env command: + + 'minikube -p {{.profile_name}} docker-env' + + `, out.V{"profile_name": name}) + } // ensureGuestClockSync ensures that the guest system clock is relatively in-sync diff --git a/pkg/minikube/machine/info.go b/pkg/minikube/machine/info.go index 99330d3850..1bae7253e9 100644 --- a/pkg/minikube/machine/info.go +++ b/pkg/minikube/machine/info.go @@ -29,13 +29,13 @@ import ( ) type hostInfo struct { - Memory int + Memory int64 CPUs int - DiskSize int + DiskSize int64 } -func megs(bytes uint64) int { - return int(bytes / 1024 / 1024) +func megs(bytes uint64) int64 { + return int64(bytes / 1024 / 1024) } func getHostInfo() (*hostInfo, error) { diff --git a/pkg/minikube/machine/machine.go b/pkg/minikube/machine/machine.go index 5b65fd59d1..fd3804ecb4 100644 --- a/pkg/minikube/machine/machine.go +++ b/pkg/minikube/machine/machine.go @@ -25,6 +25,8 @@ import ( "github.com/docker/machine/libmachine/state" "github.com/golang/glog" "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" ) @@ -84,7 +86,7 @@ func List(miniHome ...string) (validMachines []*Machine, inValidMachines []*Mach return validMachines, inValidMachines, nil } -// Load loads a machine or throws an error if the machine could not be loadedG +// Load loads a machine or throws an error if the machine could not be loaded. func Load(name string) (*Machine, error) { api, err := NewAPIClient() if err != nil { @@ -122,7 +124,8 @@ func machineDirs(miniHome ...string) (dirs []string, err error) { } // CreateSSHShell creates a new SSH shell / client -func CreateSSHShell(api libmachine.API, machineName string, args []string) error { +func CreateSSHShell(api libmachine.API, cc config.ClusterConfig, n config.Node, args []string) error { + machineName := driver.MachineName(cc, n) host, err := CheckIfHostExistsAndLoad(api, machineName) if err != nil { return errors.Wrap(err, "host exists and load") diff --git a/pkg/minikube/machine/machine_test.go b/pkg/minikube/machine/machine_test.go index 7fc9e4c557..c084650854 100644 --- a/pkg/minikube/machine/machine_test.go +++ b/pkg/minikube/machine/machine_test.go @@ -34,7 +34,7 @@ func TestListMachines(t *testing.T) { totalNumberOfMachines = numberOfValidMachines + numberOfInValidMachines ) - viper.Set(config.MachineProfile, "") + viper.Set(config.ProfileName, "") testMinikubeDir := "./testdata/list-machines/.minikube" miniDir, err := filepath.Abs(testMinikubeDir) diff --git a/pkg/minikube/machine/start.go b/pkg/minikube/machine/start.go index 1d34f28070..8f44a12b66 100644 --- a/pkg/minikube/machine/start.go +++ b/pkg/minikube/machine/start.go @@ -32,6 +32,7 @@ import ( "github.com/juju/mutex" "github.com/pkg/errors" "github.com/spf13/viper" + "k8s.io/minikube/pkg/drivers/kic/oci" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" @@ -252,6 +253,7 @@ func acquireMachinesLock(name string) (mutex.Releaser, error) { // showHostInfo shows host information func showHostInfo(cfg config.ClusterConfig) { + machineType := driver.MachineType(cfg.Driver) if driver.BareMetal(cfg.Driver) { info, err := getHostInfo() if err == nil { @@ -259,12 +261,15 @@ func showHostInfo(cfg config.ClusterConfig) { } return } - if driver.IsKIC(cfg.Driver) { - info, err := getHostInfo() // TODO medyagh: get docker-machine info for non linux + if driver.IsKIC(cfg.Driver) { // TODO:medyagh add free disk space on docker machine + s, err := oci.DaemonInfo(cfg.Driver) if err == nil { - out.T(out.StartingVM, "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "number_of_host_cpus": info.CPUs, "memory_size": cfg.Memory, "host_memory_size": info.Memory}) + var info hostInfo + info.CPUs = s.CPUs + info.Memory = megs(uint64(s.TotalMemory)) + out.T(out.StartingVM, "Creating Kubernetes in {{.driver_name}} {{.machine_type}} with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "number_of_host_cpus": info.CPUs, "memory_size": cfg.Memory, "host_memory_size": info.Memory, "machine_type": machineType}) } return } - out.T(out.StartingVM, "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "memory_size": cfg.Memory, "disk_size": cfg.DiskSize}) + out.T(out.StartingVM, "Creating {{.driver_name}} {{.machine_type}} (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "memory_size": cfg.Memory, "disk_size": cfg.DiskSize, "machine_type": machineType}) } diff --git a/pkg/minikube/node/machine.go b/pkg/minikube/node/machine.go new file mode 100644 index 0000000000..483131515a --- /dev/null +++ b/pkg/minikube/node/machine.go @@ -0,0 +1,187 @@ +/* +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 node + +import ( + "fmt" + "net" + "os" + "os/exec" + "strings" + "time" + + "github.com/docker/machine/libmachine" + "github.com/docker/machine/libmachine/host" + "github.com/golang/glog" + "github.com/spf13/viper" + "k8s.io/minikube/pkg/minikube/bootstrapper/images" + "k8s.io/minikube/pkg/minikube/command" + "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" + "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" + "k8s.io/minikube/pkg/minikube/proxy" + "k8s.io/minikube/pkg/util/retry" +) + +func startMachine(cfg *config.ClusterConfig, node *config.Node) (runner command.Runner, preExists bool, machineAPI libmachine.API, host *host.Host) { + m, err := machine.NewAPIClient() + if err != nil { + exit.WithError("Failed to get machine client", err) + } + host, preExists = startHost(m, *cfg, *node) + runner, err = machine.CommandRunner(host) + if err != nil { + exit.WithError("Failed to get command runner", err) + } + + ip := validateNetwork(host, runner) + + // Bypass proxy for minikube's vm host ip + err = proxy.ExcludeIP(ip) + if err != nil { + out.ErrT(out.FailureType, "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.", out.V{"ip": ip}) + } + // Save IP to configuration file for subsequent use + node.IP = ip + + if err := Save(cfg, node); err != nil { + exit.WithError("Failed to save config", err) + } + + return runner, preExists, m, host +} + +// startHost starts a new minikube host using a VM or None +func startHost(api libmachine.API, mc config.ClusterConfig, n config.Node) (*host.Host, bool) { + exists, err := api.Exists(mc.Name) + if err != nil { + exit.WithError("Failed to check if machine exists", err) + } + + host, err := machine.StartHost(api, mc, n) + if err != nil { + exit.WithError("Unable to start VM. Please investigate and run 'minikube delete' if possible", err) + } + return host, exists +} + +// validateNetwork tries to catch network problems as soon as possible +func validateNetwork(h *host.Host, r command.Runner) string { + ip, err := h.Driver.GetIP() + if err != nil { + exit.WithError("Unable to get VM IP address", err) + } + + optSeen := false + warnedOnce := false + for _, k := range proxy.EnvVars { + if v := os.Getenv(k); v != "" { + if !optSeen { + out.T(out.Internet, "Found network options:") + optSeen = true + } + out.T(out.Option, "{{.key}}={{.value}}", out.V{"key": k, "value": v}) + ipExcluded := proxy.IsIPExcluded(ip) // Skip warning if minikube ip is already in NO_PROXY + k = strings.ToUpper(k) // for http_proxy & https_proxy + if (k == "HTTP_PROXY" || k == "HTTPS_PROXY") && !ipExcluded && !warnedOnce { + out.WarningT("You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP ({{.ip_address}}). Please see {{.documentation_url}} for more details", out.V{"ip_address": ip, "documentation_url": "https://minikube.sigs.k8s.io/docs/reference/networking/proxy/"}) + warnedOnce = true + } + } + } + + if !driver.BareMetal(h.Driver.DriverName()) && !driver.IsKIC(h.Driver.DriverName()) { + trySSH(h, ip) + } + + tryLookup(r) + tryRegistry(r) + return ip +} + +func trySSH(h *host.Host, ip string) { + if viper.GetBool("force") { + return + } + + sshAddr := net.JoinHostPort(ip, "22") + + dial := func() (err error) { + d := net.Dialer{Timeout: 3 * time.Second} + conn, err := d.Dial("tcp", sshAddr) + if err != nil { + out.WarningT("Unable to verify SSH connectivity: {{.error}}. Will retry...", out.V{"error": err}) + return err + } + _ = conn.Close() + return nil + } + + if err := retry.Expo(dial, time.Second, 13*time.Second); err != nil { + exit.WithCodeT(exit.IO, `minikube is unable to connect to the VM: {{.error}} + + This is likely due to one of two reasons: + + - VPN or firewall interference + - {{.hypervisor}} network configuration issue + + Suggested workarounds: + + - Disable your local VPN or firewall software + - Configure your local VPN or firewall to allow access to {{.ip}} + - Restart or reinstall {{.hypervisor}} + - Use an alternative --driver + - Use --force to override this connectivity check + `, out.V{"error": err, "hypervisor": h.Driver.DriverName(), "ip": ip}) + } +} + +func tryLookup(r command.Runner) { + // DNS check + if rr, err := r.RunCmd(exec.Command("nslookup", "-type=ns", "kubernetes.io")); err != nil { + glog.Infof("%s failed: %v which might be okay will retry nslookup without query type", rr.Args, err) + // will try with without query type for ISOs with different busybox versions. + if _, err = r.RunCmd(exec.Command("nslookup", "kubernetes.io")); err != nil { + glog.Warningf("nslookup failed: %v", err) + // try with the older "host" command, instead of the newer "nslookup" + if _, err = r.RunCmd(exec.Command("host", "kubernetes.io")); err != nil { + out.WarningT("Node may be unable to resolve external DNS records") + } + } + } +} +func tryRegistry(r command.Runner) { + // Try an HTTPS connection to the image repository + proxy := os.Getenv("HTTPS_PROXY") + opts := []string{"-sS"} + if proxy != "" && !strings.HasPrefix(proxy, "localhost") && !strings.HasPrefix(proxy, "127.0") { + opts = append([]string{"-x", proxy}, opts...) + } + + repo := viper.GetString(imageRepository) + if repo == "" { + repo = images.DefaultKubernetesRepo + } + + opts = append(opts, fmt.Sprintf("https://%s/", repo)) + if rr, err := r.RunCmd(exec.Command("curl", opts...)); err != nil { + glog.Warningf("%s failed: %v", rr.Args, err) + out.WarningT("VM is unable to access {{.repository}}, you may need to configure a proxy or set --image-repository", out.V{"repository": repo}) + } +} diff --git a/pkg/minikube/node/node.go b/pkg/minikube/node/node.go index 940661bc95..fb12bfca75 100644 --- a/pkg/minikube/node/node.go +++ b/pkg/minikube/node/node.go @@ -19,9 +19,9 @@ package node import ( "errors" - "github.com/golang/glog" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/machine" ) @@ -48,27 +48,23 @@ func Add(cc *config.ClusterConfig, n config.Node) error { // Delete stops and deletes the given node from the given cluster func Delete(cc config.ClusterConfig, name string) error { - _, index, err := Retrieve(&cc, name) + n, index, err := Retrieve(&cc, name) if err != nil { return err } - if err != nil { - glog.Warningf("Failed to stop node %s. Will still try to delete.", name) - } - api, err := machine.NewAPIClient() if err != nil { return err } - err = machine.DeleteHost(api, name) + err = machine.DeleteHost(api, driver.MachineName(cc, *n)) if err != nil { return err } cc.Nodes = append(cc.Nodes[:index], cc.Nodes[index+1:]...) - return config.SaveProfile(viper.GetString(config.MachineProfile), &cc) + return config.SaveProfile(viper.GetString(config.ProfileName), &cc) } // Retrieve finds the node by name in the given cluster @@ -81,3 +77,20 @@ func Retrieve(cc *config.ClusterConfig, name string) (*config.Node, int, error) return nil, -1, errors.New("Could not find node " + name) } + +// Save saves a node to a cluster +func Save(cfg *config.ClusterConfig, node *config.Node) error { + update := false + for i, n := range cfg.Nodes { + if n.Name == node.Name { + cfg.Nodes[i] = *node + update = true + break + } + } + + if !update { + cfg.Nodes = append(cfg.Nodes, *node) + } + return config.SaveProfile(viper.GetString(config.ProfileName), cfg) +} diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go index f770b0c88d..3e88a23041 100644 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -60,7 +60,7 @@ func Start(cc config.ClusterConfig, n config.Node, existingAddons map[string]boo // enable addons, both old and new! if existingAddons != nil { - addons.Start(viper.GetString(config.MachineProfile), existingAddons, config.AddonList) + addons.Start(viper.GetString(config.ProfileName), existingAddons, config.AddonList) } if err := bs.UpdateNode(cc, n, cr); err != nil { @@ -87,7 +87,7 @@ func Start(cc config.ClusterConfig, n config.Node, existingAddons map[string]boo if err != nil { exit.WithError("Getting primary control plane", err) } - cpBs, err := cluster.Bootstrapper(mAPI, viper.GetString(cmdcfg.Bootstrapper), cc.Name, cp.Name) + cpBs, err := cluster.Bootstrapper(mAPI, viper.GetString(cmdcfg.Bootstrapper), cc, cp) if err != nil { exit.WithError("Getting bootstrapper", err) } diff --git a/pkg/minikube/problem/err_map.go b/pkg/minikube/problem/err_map.go index 54ce675b8a..ec93a3569a 100644 --- a/pkg/minikube/problem/err_map.go +++ b/pkg/minikube/problem/err_map.go @@ -66,19 +66,19 @@ var vmProblems = map[string]match{ }, "HYPERKIT_NOT_FOUND": { Regexp: re(`Driver "hyperkit" not found.`), - Advice: "Please install the minikube hyperkit VM driver, or select an alternative --vm-driver", + Advice: "Please install the minikube hyperkit VM driver, or select an alternative --driver", URL: "https://minikube.sigs.k8s.io/docs/reference/drivers/hyperkit/", GOOS: []string{"darwin"}, }, "HYPERKIT_VMNET_FRAMEWORK": { Regexp: re(`error from vmnet.framework: -1`), - Advice: "Hyperkit networking is broken. Upgrade to the latest hyperkit version and/or Docker for Desktop. Alternatively, you may choose an alternate --vm-driver", + Advice: "Hyperkit networking is broken. Upgrade to the latest hyperkit version and/or Docker for Desktop. Alternatively, you may choose an alternate --driver", Issues: []int{6028, 5594}, GOOS: []string{"darwin"}, }, "HYPERKIT_CRASHED": { Regexp: re(`hyperkit crashed!`), - Advice: "Hyperkit is broken. Upgrade to the latest hyperkit version and/or Docker for Desktop. Alternatively, you may choose an alternate --vm-driver", + Advice: "Hyperkit is broken. Upgrade to the latest hyperkit version and/or Docker for Desktop. Alternatively, you may choose an alternate --driver", Issues: []int{6079, 5780}, GOOS: []string{"darwin"}, }, @@ -109,11 +109,17 @@ var vmProblems = map[string]match{ Issues: []int{4511}, GOOS: []string{"windows"}, }, + "HYPERV_FILE_DELETE_FAILURE": { + Regexp: re(`Unable to remove machine directory`), + Advice: "You may need to stop the Hyper-V Manager and run `minikube delete` again.", + Issues: []int{6804}, + GOOS: []string{"windows"}, + }, // KVM "KVM2_NOT_FOUND": { Regexp: re(`Driver "kvm2" not found. Do you have the plugin binary .* accessible in your PATH`), - Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver", + Advice: "Please install the minikube kvm2 VM driver, or select an alternative --driver", URL: "https://minikube.sigs.k8s.io/docs/reference/drivers/kvm2/", GOOS: []string{"linux"}, }, @@ -125,7 +131,7 @@ var vmProblems = map[string]match{ }, "KVM_CREATE_CONFLICT": { Regexp: re(`KVM_CREATE_VM.* failed:.* Device or resource busy`), - Advice: "Another hypervisor, such as VirtualBox, is conflicting with KVM. Please stop the other hypervisor, or use --vm-driver to switch to it.", + Advice: "Another hypervisor, such as VirtualBox, is conflicting with KVM. Please stop the other hypervisor, or use --driver to switch to it.", Issues: []int{4913}, GOOS: []string{"linux"}, }, @@ -136,7 +142,7 @@ var vmProblems = map[string]match{ }, "KVM2_START_NO_IP": { Regexp: re(`Error in driver during machine creation: Machine didn't return an IP after 120 seconds`), - Advice: "Check your firewall rules for interference, and run 'virt-host-validate' to check for KVM configuration issues. If you are running minikube within a VM, consider using --vm-driver=none", + Advice: "Check your firewall rules for interference, and run 'virt-host-validate' to check for KVM configuration issues. If you are running minikube within a VM, consider using --driver=none", URL: "https://minikube.sigs.k8s.io/docs/reference/drivers/kvm2/", Issues: []int{4249, 3566}, GOOS: []string{"linux"}, @@ -189,7 +195,7 @@ var vmProblems = map[string]match{ }, "NONE_DOCKER_EXIT_5": { Regexp: re(`sudo systemctl start docker: exit status 5`), - Advice: "Ensure that Docker is installed and healthy: Run 'sudo systemctl start docker' and 'journalctl -u docker'. Alternatively, select another value for --vm-driver", + Advice: "Ensure that Docker is installed and healthy: Run 'sudo systemctl start docker' and 'journalctl -u docker'. Alternatively, select another value for --driver", URL: "https://minikube.sigs.k8s.io/docs/reference/drivers/none", Issues: []int{5532}, GOOS: []string{"linux"}, @@ -215,7 +221,7 @@ var vmProblems = map[string]match{ }, "NONE_DEFAULT_ROUTE": { Regexp: re(`(No|from) default routes`), - Advice: "Configure a default route on this Linux host, or use another --vm-driver that does not require it", + Advice: "Configure a default route on this Linux host, or use another --driver that does not require it", Issues: []int{6083, 5636}, GOOS: []string{"linux"}, }, @@ -264,17 +270,17 @@ var vmProblems = map[string]match{ }, "VBOX_HYPERV_64_BOOT": { Regexp: re(`VirtualBox won't boot a 64bits VM when Hyper-V is activated`), - Advice: "VirtualBox and Hyper-V are having a conflict. Use '--vm-driver=hyperv' or disable Hyper-V using: 'bcdedit /set hypervisorlaunchtype off'", + Advice: "VirtualBox and Hyper-V are having a conflict. Use '--driver=hyperv' or disable Hyper-V using: 'bcdedit /set hypervisorlaunchtype off'", Issues: []int{4051, 4783}, }, "VBOX_HYPERV_NEM_VM": { Regexp: re(`vrc=VERR_NEM_VM_CREATE_FAILED`), - Advice: "VirtualBox and Hyper-V are having a conflict. Use '--vm-driver=hyperv' or disable Hyper-V using: 'bcdedit /set hypervisorlaunchtype off'", + Advice: "VirtualBox and Hyper-V are having a conflict. Use '--driver=hyperv' or disable Hyper-V using: 'bcdedit /set hypervisorlaunchtype off'", Issues: []int{4587}, }, "VBOX_NOT_FOUND": { Regexp: re(`VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path`), - Advice: "Install VirtualBox, or select an alternative value for --vm-driver", + Advice: "Install VirtualBox, or select an alternative value for --driver", URL: "https://minikube.sigs.k8s.io/docs/start/", Issues: []int{3784}, }, @@ -285,17 +291,17 @@ var vmProblems = map[string]match{ }, "VBOX_VTX_DISABLED": { Regexp: re(`This computer doesn't have VT-X/AMD-v enabled`), - Advice: "Virtualization support is disabled on your computer. If you are running minikube within a VM, try '--vm-driver=none'. Otherwise, consult your systems BIOS manual for how to enable virtualization.", + Advice: "Virtualization support is disabled on your computer. If you are running minikube within a VM, try '--driver=none'. Otherwise, consult your systems BIOS manual for how to enable virtualization.", Issues: []int{3900, 4730}, }, "VERR_VERR_VMX_DISABLED": { Regexp: re(`VT-x is disabled.*VERR_VMX_MSR_ALL_VMX_DISABLED`), - Advice: "Virtualization support is disabled on your computer. If you are running minikube within a VM, try '--vm-driver=none'. Otherwise, consult your systems BIOS manual for how to enable virtualization.", + Advice: "Virtualization support is disabled on your computer. If you are running minikube within a VM, try '--driver=none'. Otherwise, consult your systems BIOS manual for how to enable virtualization.", Issues: []int{5282, 5456}, }, "VBOX_VERR_VMX_NO_VMX": { Regexp: re(`VT-x is not available.*VERR_VMX_NO_VMX`), - Advice: "Your host does not support virtualization. If you are running minikube within a VM, try '--vm-driver=none'. Otherwise, enable virtualization in your BIOS", + Advice: "Your host does not support virtualization. If you are running minikube within a VM, try '--driver=none'. Otherwise, enable virtualization in your BIOS", Issues: []int{1994, 5326}, }, "VBOX_HOST_NETWORK": { diff --git a/pkg/minikube/registry/drvs/docker/docker.go b/pkg/minikube/registry/drvs/docker/docker.go index af8a8f27cd..abe84081d7 100644 --- a/pkg/minikube/registry/drvs/docker/docker.go +++ b/pkg/minikube/registry/drvs/docker/docker.go @@ -37,21 +37,23 @@ func init() { Config: configure, Init: func() drivers.Driver { return kic.NewDriver(kic.Config{OCIBinary: oci.Docker}) }, Status: status, - Priority: registry.Experimental, + Priority: registry.Fallback, }); err != nil { panic(fmt.Sprintf("register failed: %v", err)) } } -func configure(mc config.ClusterConfig, n config.Node) (interface{}, error) { +func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { return kic.NewDriver(kic.Config{ - MachineName: driver.MachineName(mc.Name, n.Name), - StorePath: localpath.MiniPath(), - ImageDigest: kic.BaseImage, - CPU: mc.CPUs, - Memory: mc.Memory, - OCIBinary: oci.Docker, - APIServerPort: n.Port, + MachineName: driver.MachineName(cc, n), + StorePath: localpath.MiniPath(), + ImageDigest: kic.BaseImage, + CPU: cc.CPUs, + Memory: cc.Memory, + OCIBinary: oci.Docker, + APIServerPort: cc.Nodes[0].Port, + KubernetesVersion: cc.KubernetesConfig.KubernetesVersion, + ContainerRuntime: cc.KubernetesConfig.ContainerRuntime, }), nil } @@ -61,6 +63,10 @@ func status() registry.State { return registry.State{Error: err, Installed: false, Healthy: false, Fix: "Docker is required.", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/docker/"} } + if err := oci.PointToHostDockerDaemon(); err != nil { + return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Failed to point to dockerd. Please make sure DOCKER_HOST environment variable is pointing to your installed dockerd."} + } + // Allow no more than 3 seconds for docker info ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() diff --git a/pkg/minikube/registry/drvs/hyperkit/hyperkit.go b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go index 5fe099b79f..43ce54b6b6 100644 --- a/pkg/minikube/registry/drvs/hyperkit/hyperkit.go +++ b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go @@ -32,6 +32,7 @@ import ( "k8s.io/minikube/pkg/drivers/hyperkit" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -65,11 +66,11 @@ func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { return &hyperkit.Driver{ BaseDriver: &drivers.BaseDriver{ - MachineName: driver.MachineName(cfg.Name, n.Name), + MachineName: driver.MachineName(cfg, n), StorePath: localpath.MiniPath(), SSHUser: "docker", }, - Boot2DockerURL: cfg.Downloader.GetISOFileURI(cfg.MinikubeISO), + Boot2DockerURL: download.LocalISOResource(cfg.MinikubeISO), DiskSize: cfg.DiskSize, Memory: cfg.Memory, CPU: cfg.CPUs, @@ -78,7 +79,7 @@ func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { UUID: u, VpnKitSock: cfg.HyperkitVpnKitSock, VSockPorts: cfg.HyperkitVSockPorts, - Cmdline: "loglevel=3 console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 systemd.legacy_systemd_cgroup_controller=yes random.trust_cpu=on hw_rng_model=virtio base host=" + n.Name, + Cmdline: "loglevel=3 console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 systemd.legacy_systemd_cgroup_controller=yes random.trust_cpu=on hw_rng_model=virtio base host=" + cfg.Name, }, nil } diff --git a/pkg/minikube/registry/drvs/hyperv/hyperv.go b/pkg/minikube/registry/drvs/hyperv/hyperv.go index 55440fb711..2c6c660390 100644 --- a/pkg/minikube/registry/drvs/hyperv/hyperv.go +++ b/pkg/minikube/registry/drvs/hyperv/hyperv.go @@ -30,6 +30,7 @@ import ( "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -53,8 +54,8 @@ func init() { } func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { - d := hyperv.NewDriver(driver.MachineName(mc.Name, n.Name), localpath.MiniPath()) - d.Boot2DockerURL = cfg.Downloader.GetISOFileURI(cfg.MinikubeISO) + d := hyperv.NewDriver(driver.MachineName(cfg, n), localpath.MiniPath()) + d.Boot2DockerURL = download.LocalISOResource(cfg.MinikubeISO) d.VSwitch = cfg.HypervVirtualSwitch if d.VSwitch == "" && cfg.HypervUseExternalSwitch { switchName, adapter, err := chooseSwitch(cfg.HypervExternalAdapter) @@ -85,14 +86,22 @@ func status() registry.State { return registry.State{Error: err} } - // Allow no more than 2 seconds for querying state - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second) defer cancel() cmd := exec.CommandContext(ctx, path, "Get-WindowsOptionalFeature", "-FeatureName", "Microsoft-Hyper-V-All", "-Online") out, err := cmd.CombinedOutput() if err != nil { - return registry.State{Installed: false, Error: fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), out), Fix: "Start PowerShell as Administrator, and run: 'Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All'", Doc: docURL} + errorMessage := fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), out) + fixMessage := "Start PowerShell as Administrator, and run: 'Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All'" + + // If timed out, prompt different error and suggestion messages + // See https://github.com/kubernetes/minikube/issues/6579 + if ctx.Err() != nil { + errorMessage = fmt.Errorf("%s exited unexpectedly:\n%s", strings.Join(cmd.Args, " "), ctx.Err()) + fixMessage = "If you have Hyper-V configured correctly, please try start again with `--force` specified" + } + return registry.State{Installed: false, Error: errorMessage, Fix: fixMessage, Doc: docURL} } return registry.State{Installed: true, Healthy: true} } diff --git a/pkg/minikube/registry/drvs/kvm2/kvm2.go b/pkg/minikube/registry/drvs/kvm2/kvm2.go index 90071e6bcf..fae105572d 100644 --- a/pkg/minikube/registry/drvs/kvm2/kvm2.go +++ b/pkg/minikube/registry/drvs/kvm2/kvm2.go @@ -30,6 +30,7 @@ import ( "github.com/docker/machine/libmachine/drivers" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -67,25 +68,25 @@ type kvmDriver struct { ConnectionURI string } -func configure(mc config.ClusterConfig, n config.Node) (interface{}, error) { - name := driver.MachineName(mc.Name, n.Name) +func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { + name := driver.MachineName(cc, n) return kvmDriver{ BaseDriver: &drivers.BaseDriver{ MachineName: name, StorePath: localpath.MiniPath(), SSHUser: "docker", }, - Memory: mc.Memory, - CPU: mc.CPUs, - Network: mc.KVMNetwork, + Memory: cc.Memory, + CPU: cc.CPUs, + Network: cc.KVMNetwork, PrivateNetwork: "minikube-net", - Boot2DockerURL: mc.Downloader.GetISOFileURI(mc.MinikubeISO), - DiskSize: mc.DiskSize, + Boot2DockerURL: download.LocalISOResource(cc.MinikubeISO), + DiskSize: cc.DiskSize, DiskPath: filepath.Join(localpath.MiniPath(), "machines", name, fmt.Sprintf("%s.rawdisk", name)), ISO: filepath.Join(localpath.MiniPath(), "machines", name, "boot2docker.iso"), - GPU: mc.KVMGPU, - Hidden: mc.KVMHidden, - ConnectionURI: mc.KVMQemuURI, + GPU: cc.KVMGPU, + Hidden: cc.KVMHidden, + ConnectionURI: cc.KVMQemuURI, }, nil } diff --git a/pkg/minikube/registry/drvs/none/none.go b/pkg/minikube/registry/drvs/none/none.go index 4bf39d6d7b..26542d4d28 100644 --- a/pkg/minikube/registry/drvs/none/none.go +++ b/pkg/minikube/registry/drvs/none/none.go @@ -42,11 +42,11 @@ func init() { } } -func configure(mc config.ClusterConfig, n config.Node) (interface{}, error) { +func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { return none.NewDriver(none.Config{ - MachineName: n.Name, + MachineName: driver.MachineName(cc, n), StorePath: localpath.MiniPath(), - ContainerRuntime: mc.KubernetesConfig.ContainerRuntime, + ContainerRuntime: cc.KubernetesConfig.ContainerRuntime, }), nil } diff --git a/pkg/minikube/registry/drvs/parallels/parallels.go b/pkg/minikube/registry/drvs/parallels/parallels.go index 8f892cb0b0..1f14bb653a 100644 --- a/pkg/minikube/registry/drvs/parallels/parallels.go +++ b/pkg/minikube/registry/drvs/parallels/parallels.go @@ -25,6 +25,7 @@ import ( parallels "github.com/Parallels/docker-machine-parallels" "github.com/docker/machine/libmachine/drivers" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -45,8 +46,8 @@ func init() { } func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { - d := parallels.NewDriver(driver.MachineName(cfg.Name, n.Name), localpath.MiniPath()).(*parallels.Driver) - d.Boot2DockerURL = cfg.Downloader.GetISOFileURI(cfg.MinikubeISO) + d := parallels.NewDriver(driver.MachineName(cfg, n), localpath.MiniPath()).(*parallels.Driver) + d.Boot2DockerURL = download.LocalISOResource(cfg.MinikubeISO) d.Memory = cfg.Memory d.CPU = cfg.CPUs d.DiskSize = cfg.DiskSize diff --git a/pkg/minikube/registry/drvs/podman/podman.go b/pkg/minikube/registry/drvs/podman/podman.go index f2c9a0329f..468b1814b8 100644 --- a/pkg/minikube/registry/drvs/podman/podman.go +++ b/pkg/minikube/registry/drvs/podman/podman.go @@ -49,15 +49,15 @@ func init() { } } -func configure(mc config.ClusterConfig, n config.Node) (interface{}, error) { +func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { return kic.NewDriver(kic.Config{ - MachineName: driver.MachineName(mc.Name, n.Name), + MachineName: driver.MachineName(cc, n), StorePath: localpath.MiniPath(), ImageDigest: strings.Split(kic.BaseImage, "@")[0], // for podman does not support docker images references with both a tag and digest. - CPU: mc.CPUs, - Memory: mc.Memory, + CPU: cc.CPUs, + Memory: cc.Memory, OCIBinary: oci.Podman, - APIServerPort: n.Port, + APIServerPort: cc.Nodes[0].Port, }), nil } diff --git a/pkg/minikube/registry/drvs/virtualbox/virtualbox.go b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go index 04c084c249..0bc784b5d2 100644 --- a/pkg/minikube/registry/drvs/virtualbox/virtualbox.go +++ b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go @@ -27,6 +27,7 @@ import ( "github.com/docker/machine/libmachine/drivers" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -49,19 +50,19 @@ func init() { } } -func configure(mc config.ClusterConfig, n config.Node) (interface{}, error) { - d := virtualbox.NewDriver(driver.MachineName(mc.Name, n.Name), localpath.MiniPath()) - d.Boot2DockerURL = mc.Downloader.GetISOFileURI(mc.MinikubeISO) - d.Memory = mc.Memory - d.CPU = mc.CPUs - d.DiskSize = mc.DiskSize - d.HostOnlyCIDR = mc.HostOnlyCIDR - d.NoShare = mc.DisableDriverMounts - d.NoVTXCheck = mc.NoVTXCheck - d.NatNicType = mc.NatNicType - d.HostOnlyNicType = mc.HostOnlyNicType - d.DNSProxy = mc.DNSProxy - d.HostDNSResolver = mc.HostDNSResolver +func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { + d := virtualbox.NewDriver(driver.MachineName(cc, n), localpath.MiniPath()) + d.Boot2DockerURL = download.LocalISOResource(cc.MinikubeISO) + d.Memory = cc.Memory + d.CPU = cc.CPUs + d.DiskSize = cc.DiskSize + d.HostOnlyCIDR = cc.HostOnlyCIDR + d.NoShare = cc.DisableDriverMounts + d.NoVTXCheck = cc.NoVTXCheck + d.NatNicType = cc.NatNicType + d.HostOnlyNicType = cc.HostOnlyNicType + d.DNSProxy = cc.DNSProxy + d.HostDNSResolver = cc.HostDNSResolver return d, nil } diff --git a/pkg/minikube/registry/drvs/vmware/vmware.go b/pkg/minikube/registry/drvs/vmware/vmware.go index 65dceda11b..c6e5e0d684 100644 --- a/pkg/minikube/registry/drvs/vmware/vmware.go +++ b/pkg/minikube/registry/drvs/vmware/vmware.go @@ -22,6 +22,7 @@ import ( vmwcfg "github.com/machine-drivers/docker-machine-driver-vmware/pkg/drivers/vmware/config" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -39,12 +40,12 @@ func init() { } } -func configure(mc config.ClusterConfig, n config.Node) (interface{}, error) { - d := vmwcfg.NewConfig(driver.MachineName(mc.Name, n.Name), localpath.MiniPath()) - d.Boot2DockerURL = mc.Downloader.GetISOFileURI(mc.MinikubeISO) - d.Memory = mc.Memory - d.CPU = mc.CPUs - d.DiskSize = mc.DiskSize +func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) { + d := vmwcfg.NewConfig(driver.MachineName(cc, n), localpath.MiniPath()) + d.Boot2DockerURL = download.LocalISOResource(cc.MinikubeISO) + d.Memory = cc.Memory + d.CPU = cc.CPUs + d.DiskSize = cc.DiskSize // TODO(frapposelli): push these defaults upstream to fixup this driver d.SSHPort = 22 diff --git a/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go index 5f73cb6949..b571113941 100644 --- a/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go +++ b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go @@ -27,6 +27,7 @@ import ( "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -45,8 +46,8 @@ func init() { } func configure(cfg config.ClusterConfig, n config.Node) (interface{}, error) { - d := vmwarefusion.NewDriver(driver.MachineName(cfg.Name, n.Name), localpath.MiniPath()).(*vmwarefusion.Driver) - d.Boot2DockerURL = cfg.Downloader.GetISOFileURI(cfg.MinikubeISO) + d := vmwarefusion.NewDriver(driver.MachineName(cfg, n), localpath.MiniPath()).(*vmwarefusion.Driver) + d.Boot2DockerURL = download.LocalISOResource(cfg.MinikubeISO) d.Memory = cfg.Memory d.CPU = cfg.CPUs d.DiskSize = cfg.DiskSize diff --git a/pkg/minikube/service/service.go b/pkg/minikube/service/service.go index 8a695f7072..2d349d7a3b 100644 --- a/pkg/minikube/service/service.go +++ b/pkg/minikube/service/service.go @@ -48,9 +48,9 @@ import ( const ( defaultK8sClientTimeout = 60 * time.Second // DefaultWait is the default wait time, in seconds - DefaultWait = 20 + DefaultWait = 2 // DefaultInterval is the default interval, in seconds - DefaultInterval = 6 + DefaultInterval = 1 ) // K8sClient represents a kubernetes client @@ -81,7 +81,7 @@ func (k *K8sClientGetter) GetCoreClient() (typed_core.CoreV1Interface, error) { // GetClientset returns a clientset func (*K8sClientGetter) GetClientset(timeout time.Duration) (*kubernetes.Clientset, error) { loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - profile := viper.GetString(config.MachineProfile) + profile := viper.GetString(config.ProfileName) configOverrides := &clientcmd.ConfigOverrides{ Context: clientcmdapi.Context{ Cluster: profile, @@ -119,7 +119,7 @@ type URLs []SvcURL // GetServiceURLs returns a SvcURL object for every service in a particular namespace. // Accepts a template for formatting func GetServiceURLs(api libmachine.API, namespace string, t *template.Template) (URLs, error) { - host, err := machine.CheckIfHostExistsAndLoad(api, viper.GetString(config.MachineProfile)) + host, err := machine.CheckIfHostExistsAndLoad(api, viper.GetString(config.ProfileName)) if err != nil { return nil, err } @@ -155,7 +155,7 @@ func GetServiceURLs(api libmachine.API, namespace string, t *template.Template) // GetServiceURLsForService returns a SvcUrl object for a service in a namespace. Supports optional formatting. func GetServiceURLsForService(api libmachine.API, namespace, service string, t *template.Template) (SvcURL, error) { - host, err := machine.CheckIfHostExistsAndLoad(api, viper.GetString(config.MachineProfile)) + host, err := machine.CheckIfHostExistsAndLoad(api, viper.GetString(config.ProfileName)) if err != nil { return SvcURL{}, errors.Wrap(err, "Error checking if api exist and loading it") } diff --git a/pkg/minikube/service/service_test.go b/pkg/minikube/service/service_test.go index 47fd341f42..0368c1e240 100644 --- a/pkg/minikube/service/service_test.go +++ b/pkg/minikube/service/service_test.go @@ -417,15 +417,15 @@ func TestGetServiceURLs(t *testing.T) { defaultAPI := &tests.MockAPI{ FakeStore: tests.FakeStore{ Hosts: map[string]*host.Host{ - constants.DefaultMachineName: { - Name: constants.DefaultMachineName, + constants.DefaultClusterName: { + Name: constants.DefaultClusterName, Driver: &tests.MockDriver{}, }, }, }, } defaultTemplate := template.Must(template.New("svc-template").Parse("http://{{.IP}}:{{.Port}}")) - viper.Set(config.MachineProfile, constants.DefaultMachineName) + viper.Set(config.ProfileName, constants.DefaultClusterName) var tests = []struct { description string @@ -490,15 +490,15 @@ func TestGetServiceURLsForService(t *testing.T) { defaultAPI := &tests.MockAPI{ FakeStore: tests.FakeStore{ Hosts: map[string]*host.Host{ - constants.DefaultMachineName: { - Name: constants.DefaultMachineName, + constants.DefaultClusterName: { + Name: constants.DefaultClusterName, Driver: &tests.MockDriver{}, }, }, }, } defaultTemplate := template.Must(template.New("svc-template").Parse("http://{{.IP}}:{{.Port}}")) - viper.Set(config.MachineProfile, constants.DefaultMachineName) + viper.Set(config.ProfileName, constants.DefaultClusterName) var tests = []struct { description string @@ -830,8 +830,8 @@ func TestWaitAndMaybeOpenService(t *testing.T) { defaultAPI := &tests.MockAPI{ FakeStore: tests.FakeStore{ Hosts: map[string]*host.Host{ - constants.DefaultMachineName: { - Name: constants.DefaultMachineName, + constants.DefaultClusterName: { + Name: constants.DefaultClusterName, Driver: &tests.MockDriver{}, }, }, @@ -947,8 +947,8 @@ func TestWaitAndMaybeOpenServiceForNotDefaultNamspace(t *testing.T) { defaultAPI := &tests.MockAPI{ FakeStore: tests.FakeStore{ Hosts: map[string]*host.Host{ - constants.DefaultMachineName: { - Name: constants.DefaultMachineName, + constants.DefaultClusterName: { + Name: constants.DefaultClusterName, Driver: &tests.MockDriver{}, }, }, diff --git a/pkg/minikube/tunnel/kic/service_tunnel.go b/pkg/minikube/tunnel/kic/service_tunnel.go new file mode 100644 index 0000000000..862debcc99 --- /dev/null +++ b/pkg/minikube/tunnel/kic/service_tunnel.go @@ -0,0 +1,81 @@ +/* +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 kic + +import ( + "fmt" + + "github.com/golang/glog" + "github.com/pkg/errors" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + typed_core "k8s.io/client-go/kubernetes/typed/core/v1" +) + +// ServiceTunnel ... +type ServiceTunnel struct { + sshPort string + sshKey string + v1Core typed_core.CoreV1Interface + sshConn *sshConn +} + +// NewServiceTunnel ... +func NewServiceTunnel(sshPort, sshKey string, v1Core typed_core.CoreV1Interface) *ServiceTunnel { + return &ServiceTunnel{ + sshPort: sshPort, + sshKey: sshKey, + v1Core: v1Core, + } +} + +// Start ... +func (t *ServiceTunnel) Start(svcName, namespace string) ([]string, error) { + svc, err := t.v1Core.Services(namespace).Get(svcName, metav1.GetOptions{}) + if err != nil { + return nil, errors.Wrapf(err, "Service %s was not found in %q namespace. You may select another namespace by using 'minikube service %s -n ", svcName, namespace, svcName) + } + + t.sshConn, err = createSSHConnWithRandomPorts(svcName, t.sshPort, t.sshKey, svc) + if err != nil { + return nil, errors.Wrap(err, "creating ssh conn") + } + + go func() { + err = t.sshConn.startAndWait() + if err != nil { + glog.Errorf("error starting ssh tunnel: %v", err) + } + }() + + urls := make([]string, 0, len(svc.Spec.Ports)) + for _, port := range t.sshConn.ports { + urls = append(urls, fmt.Sprintf("http://127.0.0.1:%d", port)) + } + + return urls, nil +} + +// Stop ... +func (t *ServiceTunnel) Stop() error { + err := t.sshConn.stop() + if err != nil { + return errors.Wrap(err, "stopping ssh tunnel") + } + + return nil +} diff --git a/pkg/minikube/tunnel/kic/ssh_conn.go b/pkg/minikube/tunnel/kic/ssh_conn.go new file mode 100644 index 0000000000..bedb2cd473 --- /dev/null +++ b/pkg/minikube/tunnel/kic/ssh_conn.go @@ -0,0 +1,150 @@ +/* +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 kic + +import ( + "fmt" + "os/exec" + + "github.com/phayes/freeport" + v1 "k8s.io/api/core/v1" + + "k8s.io/minikube/pkg/minikube/out" +) + +type sshConn struct { + name string + service string + cmd *exec.Cmd + ports []int +} + +func createSSHConn(name, sshPort, sshKey string, svc *v1.Service) *sshConn { + // extract sshArgs + sshArgs := []string{ + // TODO: document the options here + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking no", + "-N", + "docker@127.0.0.1", + "-p", sshPort, + "-i", sshKey, + } + + askForSudo := false + var privilegedPorts []int32 + for _, port := range svc.Spec.Ports { + arg := fmt.Sprintf( + "-L %d:%s:%d", + port.Port, + svc.Spec.ClusterIP, + port.Port, + ) + + // check if any port is privileged + if port.Port < 1024 { + privilegedPorts = append(privilegedPorts, port.Port) + askForSudo = true + } + + sshArgs = append(sshArgs, arg) + } + + command := "ssh" + + if askForSudo { + out.T( + out.WarningType, + "The service {{.service}} requires privileged ports to be exposed: {{.ports}}", + out.V{"service": svc.Name, "ports": fmt.Sprintf("%v", privilegedPorts)}, + ) + + out.T(out.Permissions, "sudo permission will be asked for it.") + + command = "sudo" + sshArgs = append([]string{"ssh"}, sshArgs...) + } + + cmd := exec.Command(command, sshArgs...) + + return &sshConn{ + name: name, + service: svc.Name, + cmd: cmd, + } +} + +func createSSHConnWithRandomPorts(name, sshPort, sshKey string, svc *v1.Service) (*sshConn, error) { + // extract sshArgs + sshArgs := []string{ + // TODO: document the options here + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking no", + "-N", + "docker@127.0.0.1", + "-p", sshPort, + "-i", sshKey, + } + + usedPorts := make([]int, 0, len(svc.Spec.Ports)) + + for _, port := range svc.Spec.Ports { + freeport, err := freeport.GetFreePort() + if err != nil { + return nil, err + } + + arg := fmt.Sprintf( + "-L %d:%s:%d", + freeport, + svc.Spec.ClusterIP, + port.Port, + ) + + sshArgs = append(sshArgs, arg) + usedPorts = append(usedPorts, freeport) + } + + cmd := exec.Command("ssh", sshArgs...) + + return &sshConn{ + name: name, + service: svc.Name, + cmd: cmd, + ports: usedPorts, + }, nil +} + +func (c *sshConn) startAndWait() error { + out.T(out.Running, "Starting tunnel for service {{.service}}.", out.V{"service": c.service}) + + err := c.cmd.Start() + if err != nil { + return err + } + + // we ignore wait error because the process will be killed + _ = c.cmd.Wait() + + return nil +} + +func (c *sshConn) stop() error { + out.T(out.Stopping, "Stopping tunnel for service {{.service}}.", out.V{"service": c.service}) + + return c.cmd.Process.Kill() +} diff --git a/pkg/minikube/tunnel/kic/ssh_tunnel.go b/pkg/minikube/tunnel/kic/ssh_tunnel.go new file mode 100644 index 0000000000..bc5fd53a4f --- /dev/null +++ b/pkg/minikube/tunnel/kic/ssh_tunnel.go @@ -0,0 +1,149 @@ +/* +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 kic + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/golang/glog" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + typed_core "k8s.io/client-go/kubernetes/typed/core/v1" + + "k8s.io/minikube/pkg/minikube/tunnel" +) + +// SSHTunnel ... +type SSHTunnel struct { + ctx context.Context + sshPort string + sshKey string + v1Core typed_core.CoreV1Interface + LoadBalancerEmulator tunnel.LoadBalancerEmulator + conns map[string]*sshConn + connsToStop map[string]*sshConn +} + +// NewSSHTunnel ... +func NewSSHTunnel(ctx context.Context, sshPort, sshKey string, v1Core typed_core.CoreV1Interface) *SSHTunnel { + return &SSHTunnel{ + ctx: ctx, + sshPort: sshPort, + sshKey: sshKey, + v1Core: v1Core, + LoadBalancerEmulator: tunnel.NewLoadBalancerEmulator(v1Core), + conns: make(map[string]*sshConn), + connsToStop: make(map[string]*sshConn), + } +} + +// Start ... +func (t *SSHTunnel) Start() error { + for { + select { + case <-t.ctx.Done(): + _, err := t.LoadBalancerEmulator.Cleanup() + if err != nil { + glog.Errorf("error cleaning up: %v", err) + } + return err + default: + } + + services, err := t.v1Core.Services("").List(metav1.ListOptions{}) + if err != nil { + glog.Errorf("error listing services: %v", err) + } + + t.markConnectionsToBeStopped() + + for _, svc := range services.Items { + if svc.Spec.Type == v1.ServiceTypeLoadBalancer { + t.startConnection(svc) + } + } + + t.stopMarkedConnections() + + // TODO: which time to use? + time.Sleep(1 * time.Second) + } +} + +func (t *SSHTunnel) markConnectionsToBeStopped() { + for _, conn := range t.conns { + t.connsToStop[conn.name] = conn + } +} + +func (t *SSHTunnel) startConnection(svc v1.Service) { + uniqName := sshConnUniqName(svc) + existingSSHConn, ok := t.conns[uniqName] + + if ok { + // if the svc still exist we remove the conn from the stopping list + delete(t.connsToStop, existingSSHConn.name) + return + } + + // create new ssh conn + newSSHConn := createSSHConn(uniqName, t.sshPort, t.sshKey, &svc) + t.conns[newSSHConn.name] = newSSHConn + + go func() { + err := newSSHConn.startAndWait() + if err != nil { + glog.Errorf("error starting ssh tunnel: %v", err) + } + }() + + err := t.LoadBalancerEmulator.PatchServiceIP(t.v1Core.RESTClient(), svc, "127.0.0.1") + if err != nil { + glog.Errorf("error patching service: %v", err) + } +} + +func (t *SSHTunnel) stopMarkedConnections() { + for _, sshConn := range t.connsToStop { + err := sshConn.stop() + if err != nil { + glog.Errorf("error stopping ssh tunnel: %v", err) + } + delete(t.conns, sshConn.name) + delete(t.connsToStop, sshConn.name) + } +} + +// sshConnName creates a uniq name for the tunnel, using its name/clusterIP/ports. +// This allows a new process to be created if an existing service was changed, +// the new process will support the IP/Ports change occurred. +func sshConnUniqName(service v1.Service) string { + n := []string{ + service.Name, + "-", + service.Spec.ClusterIP, + } + + for _, port := range service.Spec.Ports { + n = append(n, fmt.Sprintf("-%d", port.Port)) + } + + return strings.Join(n, "") +} diff --git a/pkg/minikube/tunnel/loadbalancer_patcher.go b/pkg/minikube/tunnel/loadbalancer_patcher.go index 84b3a19ba8..e328e132f9 100644 --- a/pkg/minikube/tunnel/loadbalancer_patcher.go +++ b/pkg/minikube/tunnel/loadbalancer_patcher.go @@ -37,22 +37,28 @@ type patchConverter interface { convert(restClient rest.Interface, patch *Patch) *rest.Request } -// loadBalancerEmulator is the main struct for emulating the loadbalancer behavior. it sets the ingress to the cluster IP -type loadBalancerEmulator struct { +// LoadBalancerEmulator is the main struct for emulating the loadbalancer behavior. it sets the ingress to the cluster IP +type LoadBalancerEmulator struct { coreV1Client typed_core.CoreV1Interface requestSender requestSender patchConverter patchConverter } -func (l *loadBalancerEmulator) PatchServices() ([]string, error) { +func (l *LoadBalancerEmulator) PatchServices() ([]string, error) { return l.applyOnLBServices(l.updateService) } -func (l *loadBalancerEmulator) Cleanup() ([]string, error) { +func (l *LoadBalancerEmulator) PatchServiceIP(restClient rest.Interface, svc core.Service, ip string) error { + // TODO: do not ignore result + _, err := l.updateServiceIP(restClient, svc, ip) + return err +} + +func (l *LoadBalancerEmulator) Cleanup() ([]string, error) { return l.applyOnLBServices(l.cleanupService) } -func (l *loadBalancerEmulator) applyOnLBServices(action func(restClient rest.Interface, svc core.Service) ([]byte, error)) ([]string, error) { +func (l *LoadBalancerEmulator) applyOnLBServices(action func(restClient rest.Interface, svc core.Service) ([]byte, error)) ([]string, error) { services := l.coreV1Client.Services("") serviceList, err := services.List(meta.ListOptions{}) if err != nil { @@ -79,14 +85,22 @@ func (l *loadBalancerEmulator) applyOnLBServices(action func(restClient rest.Int } return managedServices, nil } -func (l *loadBalancerEmulator) updateService(restClient rest.Interface, svc core.Service) ([]byte, error) { + +func (l *LoadBalancerEmulator) updateService(restClient rest.Interface, svc core.Service) ([]byte, error) { clusterIP := svc.Spec.ClusterIP ingresses := svc.Status.LoadBalancer.Ingress if len(ingresses) == 1 && ingresses[0].IP == clusterIP { return nil, nil } + return l.updateServiceIP(restClient, svc, clusterIP) +} + +func (l *LoadBalancerEmulator) updateServiceIP(restClient rest.Interface, svc core.Service, ip string) ([]byte, error) { + if len(ip) == 0 { + return nil, nil + } glog.V(3).Infof("[%s] setting ClusterIP as the LoadBalancer Ingress", svc.Name) - jsonPatch := fmt.Sprintf(`[{"op": "add", "path": "/status/loadBalancer/ingress", "value": [ { "ip": "%s" } ] }]`, clusterIP) + jsonPatch := fmt.Sprintf(`[{"op": "add", "path": "/status/loadBalancer/ingress", "value": [ { "ip": "%s" } ] }]`, ip) patch := &Patch{ Type: types.JSONPatchType, ResourceName: svc.Name, @@ -99,14 +113,14 @@ func (l *loadBalancerEmulator) updateService(restClient rest.Interface, svc core request := l.patchConverter.convert(restClient, patch) result, err := l.requestSender.send(request) if err != nil { - glog.Errorf("error patching %s with IP %s: %s", svc.Name, clusterIP, err) + glog.Errorf("error patching %s with IP %s: %s", svc.Name, ip, err) } else { - glog.Infof("Patched %s with IP %s", svc.Name, clusterIP) + glog.Infof("Patched %s with IP %s", svc.Name, ip) } return result, err } -func (l *loadBalancerEmulator) cleanupService(restClient rest.Interface, svc core.Service) ([]byte, error) { +func (l *LoadBalancerEmulator) cleanupService(restClient rest.Interface, svc core.Service) ([]byte, error) { ingresses := svc.Status.LoadBalancer.Ingress if len(ingresses) == 0 { return nil, nil @@ -129,8 +143,8 @@ func (l *loadBalancerEmulator) cleanupService(restClient rest.Interface, svc cor } -func newLoadBalancerEmulator(corev1Client typed_core.CoreV1Interface) loadBalancerEmulator { - return loadBalancerEmulator{ +func NewLoadBalancerEmulator(corev1Client typed_core.CoreV1Interface) LoadBalancerEmulator { + return LoadBalancerEmulator{ coreV1Client: corev1Client, requestSender: &defaultRequestSender{}, patchConverter: &defaultPatchConverter{}, diff --git a/pkg/minikube/tunnel/loadbalancer_patcher_test.go b/pkg/minikube/tunnel/loadbalancer_patcher_test.go index 3143f4cb7d..1e6788f90d 100644 --- a/pkg/minikube/tunnel/loadbalancer_patcher_test.go +++ b/pkg/minikube/tunnel/loadbalancer_patcher_test.go @@ -87,7 +87,7 @@ func TestEmptyListOfServicesDoesNothing(t *testing.T) { client := newStubCoreClient(&core.ServiceList{ Items: []core.Service{}}) - patcher := newLoadBalancerEmulator(client) + patcher := NewLoadBalancerEmulator(client) serviceNames, err := patcher.PatchServices() @@ -113,7 +113,7 @@ func TestServicesWithNoLoadbalancerType(t *testing.T) { }, }) - patcher := newLoadBalancerEmulator(client) + patcher := NewLoadBalancerEmulator(client) serviceNames, err := patcher.PatchServices() @@ -214,7 +214,7 @@ func TestServicesWithLoadbalancerType(t *testing.T) { requestSender := &countingRequestSender{} patchConverter := &recordingPatchConverter{} - patcher := newLoadBalancerEmulator(client) + patcher := NewLoadBalancerEmulator(client) patcher.requestSender = requestSender patcher.patchConverter = patchConverter @@ -328,7 +328,7 @@ func TestCleanupPatchedIPs(t *testing.T) { requestSender := &countingRequestSender{} patchConverter := &recordingPatchConverter{} - patcher := newLoadBalancerEmulator(client) + patcher := NewLoadBalancerEmulator(client) patcher.requestSender = requestSender patcher.patchConverter = patchConverter diff --git a/pkg/minikube/tunnel/tunnel.go b/pkg/minikube/tunnel/tunnel.go index ab83bed1d3..375f032057 100644 --- a/pkg/minikube/tunnel/tunnel.go +++ b/pkg/minikube/tunnel/tunnel.go @@ -72,7 +72,7 @@ func newTunnel(machineName string, machineAPI libmachine.API, configLoader confi clusterInspector: ci, router: router, registry: registry, - loadBalancerEmulator: newLoadBalancerEmulator(v1Core), + LoadBalancerEmulator: NewLoadBalancerEmulator(v1Core), status: &Status{ TunnelID: id, MinikubeState: state, @@ -88,7 +88,7 @@ type tunnel struct { // collaborators clusterInspector *clusterInspector router router - loadBalancerEmulator loadBalancerEmulator + LoadBalancerEmulator LoadBalancerEmulator reporter reporter registry *persistentRegistry @@ -108,7 +108,7 @@ func (t *tunnel) cleanup() *Status { } } if t.status.MinikubeState == Running { - t.status.PatchedServices, t.status.LoadBalancerEmulatorError = t.loadBalancerEmulator.Cleanup() + t.status.PatchedServices, t.status.LoadBalancerEmulatorError = t.LoadBalancerEmulator.Cleanup() } return t.status } @@ -122,7 +122,7 @@ func (t *tunnel) update() *Status { glog.V(3).Infof("minikube is running, trying to add route%s", t.status.TunnelID.Route) setupRoute(t, h) if t.status.RouteError == nil { - t.status.PatchedServices, t.status.LoadBalancerEmulatorError = t.loadBalancerEmulator.PatchServices() + t.status.PatchedServices, t.status.LoadBalancerEmulatorError = t.LoadBalancerEmulator.PatchServices() } } glog.V(3).Infof("sending report %s", t.status) diff --git a/pkg/util/downloader.go b/pkg/util/downloader.go deleted file mode 100644 index 72b4782565..0000000000 --- a/pkg/util/downloader.go +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "net/url" - "os" - "path/filepath" - "time" - - "github.com/golang/glog" - "github.com/hashicorp/go-getter" - "github.com/juju/mutex" - "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/constants" - "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/out" - "k8s.io/minikube/pkg/util/lock" -) - -const fileScheme = "file" - -// ISODownloader downloads an ISO -type ISODownloader interface { - GetISOFileURI(isoURL string) string - CacheMinikubeISOFromURL(isoURL string) error -} - -// DefaultDownloader is the default ISODownloader -type DefaultDownloader struct{} - -// GetISOFileURI gets the local destination for a remote source -func (f DefaultDownloader) GetISOFileURI(isoURL string) string { - urlObj, err := url.Parse(isoURL) - if err != nil { - return isoURL - } - if urlObj.Scheme == fileScheme { - return isoURL - } - isoPath := filepath.Join(localpath.MiniPath(), "cache", "iso", filepath.Base(isoURL)) - // As this is a file URL there should be no backslashes regardless of platform running on. - return "file://" + filepath.ToSlash(isoPath) -} - -// CacheMinikubeISOFromURL downloads the ISO, if it doesn't exist in cache -func (f DefaultDownloader) CacheMinikubeISOFromURL(url string) error { - dst := f.GetISOCacheFilepath(url) - - // Lock before we check for existence to avoid thundering herd issues - spec := lock.PathMutexSpec(dst) - spec.Timeout = 10 * time.Minute - glog.Infof("acquiring lock: %+v", spec) - releaser, err := mutex.Acquire(spec) - if err != nil { - return errors.Wrapf(err, "unable to acquire lock for %+v", spec) - } - defer releaser.Release() - - if !f.ShouldCacheMinikubeISO(url) { - glog.Infof("Not caching ISO, using %s", url) - return nil - } - - urlWithChecksum := url - if url == constants.DefaultISOURL { - urlWithChecksum = url + "?checksum=file:" + constants.DefaultISOSHAURL - } - - // Predictable temp destination so that resume can function - tmpDst := dst + ".download" - - opts := []getter.ClientOption{getter.WithProgress(DefaultProgressBar)} - client := &getter.Client{ - Src: urlWithChecksum, - Dst: tmpDst, - Mode: getter.ClientModeFile, - Options: opts, - } - - glog.Infof("full url: %s", urlWithChecksum) - out.T(out.ISODownload, "Downloading VM boot image ...") - if err := client.Get(); err != nil { - return errors.Wrap(err, url) - } - return os.Rename(tmpDst, dst) -} - -// ShouldCacheMinikubeISO returns if we need to download the ISO -func (f DefaultDownloader) ShouldCacheMinikubeISO(isoURL string) bool { - // store the minikube-iso inside the .minikube dir - - urlObj, err := url.Parse(isoURL) - if err != nil { - return false - } - if urlObj.Scheme == fileScheme { - return false - } - if f.IsMinikubeISOCached(isoURL) { - return false - } - return true -} - -// GetISOCacheFilepath returns the path of an ISO in the local cache -func (f DefaultDownloader) GetISOCacheFilepath(isoURL string) string { - return filepath.Join(localpath.MiniPath(), "cache", "iso", filepath.Base(isoURL)) -} - -// IsMinikubeISOCached returns if an ISO exists in the local cache -func (f DefaultDownloader) IsMinikubeISOCached(isoURL string) bool { - if _, err := os.Stat(f.GetISOCacheFilepath(isoURL)); os.IsNotExist(err) { - return false - } - return true -} diff --git a/pkg/util/downloader_test.go b/pkg/util/downloader_test.go deleted file mode 100644 index 3db8593296..0000000000 --- a/pkg/util/downloader_test.go +++ /dev/null @@ -1,117 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "bytes" - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "testing" - - "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/tests" -) - -func TestGetISOFileURI(t *testing.T) { - dler := DefaultDownloader{} - - tests := map[string]string{ - "file:///test/path/minikube-test.iso": "file:///test/path/minikube-test.iso", - "https://storage.googleapis.com/minikube/iso/minikube-test.iso": "file://" + filepath.ToSlash(filepath.Join(localpath.MiniPath(), "cache", "iso", "minikube-test.iso")), - } - - for input, expected := range tests { - if isoFileURI := dler.GetISOFileURI(input); isoFileURI != expected { - t.Fatalf("Expected GetISOFileURI with input %s to return %s but instead got: %s", input, expected, isoFileURI) - } - } - -} - -var testISOString = "hello" - -func TestCacheMinikubeISOFromURL(t *testing.T) { - tempDir := tests.MakeTempDir() - defer os.RemoveAll(tempDir) - dler := DefaultDownloader{} - isoPath := filepath.Join(localpath.MiniPath(), "cache", "iso", "minikube-test.iso") - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if _, err := io.WriteString(w, testISOString); err != nil { - t.Fatalf("WriteString: %v", err) - } - })) - isoURL := server.URL + "/minikube-test.iso" - if err := dler.CacheMinikubeISOFromURL(isoURL); err != nil { - t.Fatalf("Unexpected error from CacheMinikubeISOFromURL: %v", err) - } - - transferred, err := ioutil.ReadFile(filepath.Join(isoPath)) - if err != nil { - t.Fatalf("File not copied. Could not open file at path: %s", isoPath) - } - - // test that the ISO is transferred properly - contents := []byte(testISOString) - if !bytes.Contains(transferred, contents) { - t.Fatalf("Expected transfers to contain: %s. It was: %s", contents, transferred) - } - -} - -func TestShouldCacheMinikubeISO(t *testing.T) { - dler := DefaultDownloader{} - - tests := map[string]bool{ - "file:///test/path/minikube-test.iso": false, - "https://storage.googleapis.com/minikube/iso/minikube-test.iso": true, - } - - for input, expected := range tests { - if out := dler.ShouldCacheMinikubeISO(input); out != expected { - t.Fatalf("Expected ShouldCacheMinikubeISO with input %s to return %t but instead got: %t", input, expected, out) - } - } -} - -func TestIsMinikubeISOCached(t *testing.T) { - tempDir := tests.MakeTempDir() - defer os.RemoveAll(tempDir) - - dler := DefaultDownloader{} - - testFileURI := "file:///test/path/minikube-test.iso" - expected := false - - if out := dler.IsMinikubeISOCached(testFileURI); out != expected { - t.Fatalf("Expected IsMinikubeISOCached with input %s to return %t but instead got: %t", testFileURI, expected, out) - } - - if err := ioutil.WriteFile(filepath.Join(localpath.MiniPath(), "cache", "iso", "minikube-test.iso"), []byte(testISOString), os.FileMode(int(0644))); err != nil { - t.Fatalf("WriteFile: %v", err) - } - - expected = true - if out := dler.IsMinikubeISOCached(testFileURI); out != expected { - t.Fatalf("Expected IsMinikubeISOCached with input %s to return %t but instead got: %t", testFileURI, expected, out) - } - -} diff --git a/pkg/version/version.go b/pkg/version/version.go index 727035115b..a3b921c5ca 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -25,8 +25,6 @@ import ( // VersionPrefix is the prefix of the git tag for a version const VersionPrefix = "v" -// The current version of the minikube - // version is a private field and should be set when compiling with --ldflags="-X k8s.io/minikube/pkg/version.version=vX.Y.Z" var version = "v0.0.0-unset" @@ -36,8 +34,6 @@ var gitCommitID = "" // isoVersion is a private field and should be set when compiling with --ldflags="-X k8s.io/minikube/pkg/version.isoVersion=vX.Y.Z" var isoVersion = "v0.0.0-unset" -var isoPath = "minikube/iso" - // GetVersion returns the current minikube version func GetVersion() string { return version @@ -53,11 +49,6 @@ func GetISOVersion() string { return isoVersion } -// GetISOPath returns the remote path to the minikube.iso -func GetISOPath() string { - return isoPath -} - // GetSemverVersion returns the current minikube semantic version (semver) func GetSemverVersion() (semver.Version, error) { return semver.Make(strings.TrimPrefix(GetVersion(), VersionPrefix)) diff --git a/site/content/en/docs/Contributing/drivers.en.md b/site/content/en/docs/Contributing/drivers.en.md index 6c3f4a74a8..c1dd9372c3 100644 --- a/site/content/en/docs/Contributing/drivers.en.md +++ b/site/content/en/docs/Contributing/drivers.en.md @@ -8,7 +8,7 @@ description: > This document is written for contributors who are familiar with minikube, who would like to add support for a new VM driver. -minikube relies on docker-machine drivers to manage machines. This document discusses how to modify minikube, so that this driver may be used by `minikube start --vm-driver=`. +minikube relies on docker-machine drivers to manage machines. This document discusses how to modify minikube, so that this driver may be used by `minikube start --driver=`. ## Creating a new driver @@ -46,7 +46,7 @@ struct to define a driver metadata. Essentially, you need to define 4 things at pretty simple once you understand your driver well: - Name: unique name of the driver, it will be used as the unique ID in registry and as -`--vm-driver` option in minikube command +`--driver` option in minikube command - Builtin: `true` if the driver should be builtin to minikube (preferred). `false` otherwise. @@ -87,7 +87,7 @@ func init() { func createVMwareFusionHost(config cfg.ClusterConfig) interface{} { d := vmwarefusion.NewDriver(config.Name, localpath.MiniPath()).(*vmwarefusion.Driver) - d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) + d.Boot2DockerURL = download.LocalISOResource(config.MinikubeISO) d.Memory = config.Memory d.CPU = config.CPUs d.DiskSize = config.DiskSize diff --git a/site/content/en/docs/Contributing/roadmap.en.md b/site/content/en/docs/Contributing/roadmap.en.md index 02d21ce9f5..37b135a78f 100644 --- a/site/content/en/docs/Contributing/roadmap.en.md +++ b/site/content/en/docs/Contributing/roadmap.en.md @@ -6,7 +6,7 @@ description: > Development Roadmap --- -This roadmap is a living document outlining the major technical improvements which we would like to see in minikube during 2019, divided by how they apply to our [guiding principles](principles.md) +This roadmap is a living document outlining the major technical improvements which we would like to see in minikube during 2020, divided by how they apply to our [guiding principles](principles.md) Please send a PR to suggest any improvements to it. diff --git a/site/content/en/docs/Contributing/testing.en.md b/site/content/en/docs/Contributing/testing.en.md index 693170241b..bc8e02eae5 100644 --- a/site/content/en/docs/Contributing/testing.en.md +++ b/site/content/en/docs/Contributing/testing.en.md @@ -26,7 +26,7 @@ make integration You may find it useful to set various options to test only a particular test against a non-default driver. For instance: ```shell - env TEST_ARGS="-minikube-start-args=--vm-driver=hyperkit -test.run TestStartStop" make integration + env TEST_ARGS="-minikube-start-args=--driver=hyperkit -test.run TestStartStop" make integration ``` ### Conformance Tests diff --git a/site/content/en/docs/Reference/Commands/config.md b/site/content/en/docs/Reference/Commands/config.md index 5a284951a0..8694d6cb0d 100644 --- a/site/content/en/docs/Reference/Commands/config.md +++ b/site/content/en/docs/Reference/Commands/config.md @@ -9,11 +9,11 @@ description: > ### Overview -config modifies minikube config files using subcommands like "minikube config set vm-driver kvm" +config modifies minikube config files using subcommands like "minikube config set driver kvm" Configurable fields: - * vm-driver + * driver * container-runtime * feature-gates * v diff --git a/site/content/en/docs/Reference/Commands/start.md b/site/content/en/docs/Reference/Commands/start.md index 8c9bc178f8..0a7dbecd13 100644 --- a/site/content/en/docs/Reference/Commands/start.md +++ b/site/content/en/docs/Reference/Commands/start.md @@ -42,7 +42,7 @@ minikube start [flags] Valid components are: kubelet, kubeadm, apiserver, controller-manager, etcd, proxy, scheduler - Valid kubeadm parameters: ignore-preflight-errors, dry-run, kubeconfig, kubeconfig-dir, node-name, cri-socket, experimental-upload-certs, certificate-key, rootfs, pod-network-cidr + Valid kubeadm parameters: ignore-preflight-errors, dry-run, kubeconfig, kubeconfig-dir, node-name, cri-socket, experimental-upload-certs, certificate-key, rootfs, skip-phases, pod-network-cidr --feature-gates string A set of key=value pairs that describe feature gates for alpha/experimental features. --force Force minikube to perform possibly dangerous operations diff --git a/site/content/en/docs/Reference/Configuration/minikube.md b/site/content/en/docs/Reference/Configuration/minikube.md index 608932fc93..8fc3c39438 100644 --- a/site/content/en/docs/Reference/Configuration/minikube.md +++ b/site/content/en/docs/Reference/Configuration/minikube.md @@ -54,7 +54,7 @@ Example: ```shell Configurable fields: - * vm-driver + * driver * feature-gates * v * cpus @@ -107,7 +107,7 @@ Example output: ```shell - memory: 4096 - registry: true -- vm-driver: vmware +- driver: vmware - dashboard: true - gvisor: true ``` @@ -122,7 +122,7 @@ minikube config set For example: ```shell -minikube config set vm-driver hyperkit +minikube config set driver hyperkit ``` ## Environment Configuration diff --git a/site/content/en/docs/Reference/Drivers/includes/hyperkit_usage.inc b/site/content/en/docs/Reference/Drivers/includes/hyperkit_usage.inc index 9c724b9e24..2ce954f9b1 100644 --- a/site/content/en/docs/Reference/Drivers/includes/hyperkit_usage.inc +++ b/site/content/en/docs/Reference/Drivers/includes/hyperkit_usage.inc @@ -19,11 +19,11 @@ brew install hyperkit Start a cluster using the hyperkit driver: ```shell -minikube start --vm-driver=hyperkit +minikube start --driver=hyperkit ``` To make hyperkit the default driver: ```shell -minikube config set vm-driver hyperkit +minikube config set driver hyperkit ``` diff --git a/site/content/en/docs/Reference/Drivers/includes/hyperv_usage.inc b/site/content/en/docs/Reference/Drivers/includes/hyperv_usage.inc index 6fa1c11ea7..dbe1097afb 100644 --- a/site/content/en/docs/Reference/Drivers/includes/hyperv_usage.inc +++ b/site/content/en/docs/Reference/Drivers/includes/hyperv_usage.inc @@ -16,10 +16,10 @@ If Hyper-V was not previously active, you will need to reboot. ## Usage ```shell -minikube start --vm-driver=hyperv +minikube start --driver=hyperv ``` To make hyperv the default driver: ```shell -minikube config set vm-driver hyperv +minikube config set driver hyperv ``` diff --git a/site/content/en/docs/Reference/Drivers/includes/kvm2_usage.inc b/site/content/en/docs/Reference/Drivers/includes/kvm2_usage.inc index e933991fc0..b8ba08120b 100644 --- a/site/content/en/docs/Reference/Drivers/includes/kvm2_usage.inc +++ b/site/content/en/docs/Reference/Drivers/includes/kvm2_usage.inc @@ -26,10 +26,10 @@ virt-host-validate Start a cluster using the kvm2 driver: ```shell -minikube start --vm-driver=kvm2 +minikube start --driver=kvm2 ``` To make kvm2 the default driver: ```shell -minikube config set vm-driver kvm2 +minikube config set driver kvm2 ``` diff --git a/site/content/en/docs/Reference/Drivers/includes/none_usage.inc b/site/content/en/docs/Reference/Drivers/includes/none_usage.inc index 634819ae72..f3f915a076 100644 --- a/site/content/en/docs/Reference/Drivers/includes/none_usage.inc +++ b/site/content/en/docs/Reference/Drivers/includes/none_usage.inc @@ -7,11 +7,11 @@ VM running a systemd-based Linux distribution ([see #2704](https://github.com/ku The none driver requires minikube to be run as root, until [#3760](https://github.com/kubernetes/minikube/issues/3760) can be addressed. ```shell -sudo minikube start --vm-driver=none +sudo minikube start --driver=none ``` To make `none` the default driver: ```shell -sudo minikube config set vm-driver none +sudo minikube config set driver none ``` diff --git a/site/content/en/docs/Reference/Drivers/includes/parallels_usage.inc b/site/content/en/docs/Reference/Drivers/includes/parallels_usage.inc index 49c92e1d0d..219590de86 100644 --- a/site/content/en/docs/Reference/Drivers/includes/parallels_usage.inc +++ b/site/content/en/docs/Reference/Drivers/includes/parallels_usage.inc @@ -24,11 +24,11 @@ curl -LO $(curl -s $r/releases/latest | grep -o 'http.*parallels' | head -n1) \ Start a cluster using the parallels driver: ```shell -minikube start --vm-driver=parallels +minikube start --driver=parallels ``` To make parallels the default driver: ```shell -minikube config set vm-driver parallels +minikube config set driver parallels ``` diff --git a/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc b/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc index 6bce73731a..8c0cc15244 100644 --- a/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc +++ b/site/content/en/docs/Reference/Drivers/includes/virtualbox_usage.inc @@ -7,10 +7,10 @@ Start a cluster using the virtualbox driver: ```shell -minikube start --vm-driver=virtualbox +minikube start --driver=virtualbox ``` To make virtualbox the default driver: ```shell -minikube config set vm-driver virtualbox +minikube config set driver virtualbox ``` diff --git a/site/content/en/docs/Reference/Drivers/includes/vmware_macos_usage.inc b/site/content/en/docs/Reference/Drivers/includes/vmware_macos_usage.inc index bd6832c915..75bc5ecdb3 100644 --- a/site/content/en/docs/Reference/Drivers/includes/vmware_macos_usage.inc +++ b/site/content/en/docs/Reference/Drivers/includes/vmware_macos_usage.inc @@ -24,10 +24,10 @@ curl -LO $(curl -s $r/releases/latest | grep -o 'http.*darwin_amd64' | head -n1) Start a cluster using the vmware driver: ```shell -minikube start --vm-driver=vmware +minikube start --driver=vmware ``` To make vmware the default driver: ```shell -minikube config set vm-driver vmware +minikube config set driver vmware ``` diff --git a/site/content/en/docs/Reference/Drivers/none.md b/site/content/en/docs/Reference/Drivers/none.md index 2731f13d46..2040128bdf 100644 --- a/site/content/en/docs/Reference/Drivers/none.md +++ b/site/content/en/docs/Reference/Drivers/none.md @@ -50,11 +50,11 @@ As Kubernetes has full access to both your filesystem as well as your docker ima ### Other -* `-p` (profiles) are unsupported: It is not possible to run more than one `--vm-driver=none` instance +* `-p` (profiles) are unsupported: It is not possible to run more than one `--driver=none` instance * Many `minikube` commands are not supported, such as: `dashboard`, `mount`, `ssh` * minikube with the `none` driver has a confusing permissions model, as some commands need to be run as root ("start"), and others by a regular user ("dashboard") * CoreDNS detects resolver loop, goes into CrashLoopBackOff - [#3511](https://github.com/kubernetes/minikube/issues/3511) -* Some versions of Linux have a version of docker that is newer than what Kubernetes expects. To overwrite this, run minikube with the following parameters: `sudo -E minikube start --vm-driver=none --kubernetes-version v1.11.8 --extra-config kubeadm.ignore-preflight-errors=SystemVerification` +* Some versions of Linux have a version of docker that is newer than what Kubernetes expects. To overwrite this, run minikube with the following parameters: `sudo -E minikube start --driver=none --kubernetes-version v1.11.8 --extra-config kubeadm.ignore-preflight-errors=SystemVerification` * [Full list of open 'none' driver issues](https://github.com/kubernetes/minikube/labels/co%2Fnone-driver) diff --git a/site/content/en/docs/Reference/persistent_volumes.md b/site/content/en/docs/Reference/persistent_volumes.md index fd7a82b456..6b7a38b83b 100644 --- a/site/content/en/docs/Reference/persistent_volumes.md +++ b/site/content/en/docs/Reference/persistent_volumes.md @@ -7,7 +7,7 @@ description: > About persistent volumes (hostPath) --- -minikube supports [PersistentVolumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) of type `hostPath` out of the box. These PersistentVolumes are mapped to a directory inside the running Minikube instance (usually a VM, unless you use `--vm-driver=none`). For more information on how this works, read the Dynamic Provisioning section below. +minikube supports [PersistentVolumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) of type `hostPath` out of the box. These PersistentVolumes are mapped to a directory inside the running Minikube instance (usually a VM, unless you use `--driver=none`, `--driver=docker`, or `--driver=podman`). For more information on how this works, read the Dynamic Provisioning section below. ## A note on mounts, persistence, and minikube hosts diff --git a/site/content/en/docs/Tasks/loadbalancer.md b/site/content/en/docs/Tasks/loadbalancer.md index 3807363165..4ec2f0f06d 100644 --- a/site/content/en/docs/Tasks/loadbalancer.md +++ b/site/content/en/docs/Tasks/loadbalancer.md @@ -14,7 +14,7 @@ A LoadBalancer service is the standard way to expose a service to the internet. ## Using `minikube tunnel` -Services of type `LoadBalancer` can be exposed via the `minikube tunnel` command. It will run in a separate terminal until Ctrl-C is hit. +Services of type `LoadBalancer` can be exposed via the `minikube tunnel` command. It must be run in a separate terminal window to keep the `LoadBalancer` running. Ctrl-C in the terminal can be used to terminate the process at which time the network routes will be cleaned up. ## Example @@ -25,7 +25,7 @@ it will ask for password. minikube tunnel ``` -`minikube tunnel` runs as a separate daemon, creating a network route on the host to the service CIDR of the cluster using the cluster's IP address as a gateway. The tunnel command exposes the external IP directly to any program running on the host operating system. +`minikube tunnel` runs as a process, creating a network route on the host to the service CIDR of the cluster using the cluster's IP address as a gateway. The tunnel command exposes the external IP directly to any program running on the host operating system.
diff --git a/site/content/en/docs/Tutorials/continuous_integration.md b/site/content/en/docs/Tutorials/continuous_integration.md index aa904e7667..4dad6cc9ed 100644 --- a/site/content/en/docs/Tutorials/continuous_integration.md +++ b/site/content/en/docs/Tutorials/continuous_integration.md @@ -37,5 +37,5 @@ export KUBECONFIG=$HOME/.kube/config mkdir -p $HOME/.kube $HOME/.minikube touch $KUBECONFIG -sudo -E minikube start --vm-driver=none +sudo -E minikube start --driver=none ``` diff --git a/site/content/en/docs/Tutorials/nvidia_gpu.md b/site/content/en/docs/Tutorials/nvidia_gpu.md index 74aabee72a..68846ae15b 100644 --- a/site/content/en/docs/Tutorials/nvidia_gpu.md +++ b/site/content/en/docs/Tutorials/nvidia_gpu.md @@ -15,7 +15,7 @@ description: > ## Using the KVM2 driver -When using NVIDIA GPUs with the kvm2 vm-driver, we passthrough spare GPUs on the +When using NVIDIA GPUs with the kvm2 driver, we passthrough spare GPUs on the host to the minikube VM. Doing so has a few prerequisites: - You must install the [kvm2 driver](/docs/start/linux/#hypervisor-setup). If you already had @@ -44,7 +44,7 @@ host to the minikube VM. Doing so has a few prerequisites: - Once you reboot the system after doing the above, you should be ready to use GPUs with kvm2. Run the following command to start minikube: ```shell - minikube start --vm-driver kvm2 --kvm-gpu + minikube start --driver kvm2 --kvm-gpu ``` This command will check if all the above conditions are satisfied and @@ -78,7 +78,7 @@ are disruptive to the host, so we decided to not do them automatically. ## Using the 'none' driver NOTE: This approach used to expose GPUs here is different than the approach used -to expose GPUs with `--vm-driver=kvm2`. Please don't mix these instructions. +to expose GPUs with `--driver=kvm2`. Please don't mix these instructions. - Install minikube. @@ -88,7 +88,7 @@ to expose GPUs with `--vm-driver=kvm2`. Please don't mix these instructions. - Start minikube: ```shell - minikube start --vm-driver=none --apiserver-ips 127.0.0.1 --apiserver-name localhost + minikube start --driver=none --apiserver-ips 127.0.0.1 --apiserver-name localhost ``` - Install NVIDIA's device plugin: diff --git a/test/integration/aaa_download_only_test.go b/test/integration/aaa_download_only_test.go index e0bf1fba32..e4ca5ebb26 100644 --- a/test/integration/aaa_download_only_test.go +++ b/test/integration/aaa_download_only_test.go @@ -20,18 +20,25 @@ package integration import ( "context" + "crypto/md5" "encoding/json" "fmt" + "io/ioutil" "os" "os/exec" "path/filepath" "runtime" "strings" "testing" + "time" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/daemon" + "k8s.io/minikube/pkg/drivers/kic" "k8s.io/minikube/pkg/minikube/bootstrapper/images" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/download" "k8s.io/minikube/pkg/minikube/localpath" ) @@ -72,7 +79,7 @@ func TestDownloadOnly(t *testing.T) { t.Errorf("kubeadm images: %v %+v", v, err) } - // skip verify for cache images if --vm-driver=none + // skip verify for cache images if --driver=none if !NoneDriver() { for _, img := range imgs { img = strings.Replace(img, ":", "_", 1) // for example kube-scheduler:v1.15.2 --> kube-scheduler_v1.15.2 @@ -160,3 +167,52 @@ func TestDownloadOnly(t *testing.T) { }) } +func TestDownloadOnlyDocker(t *testing.T) { + if !runningDockerDriver(StartArgs()) { + t.Skip("this test only runs with the docker driver") + } + + profile := UniqueProfileName("download-docker") + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) + defer Cleanup(t, profile, cancel) + + args := []string{"start", "--download-only", "-p", profile, "--force", "--alsologtostderr", "--driver=docker"} + rr, err := Run(t, exec.CommandContext(ctx, Target(), args...)) + if err != nil { + t.Errorf("%s failed: %v:\n%s", args, err, rr.Output()) + } + + // Make sure the downloaded image tarball exists + tarball := download.TarballPath(constants.DefaultKubernetesVersion) + contents, err := ioutil.ReadFile(tarball) + if err != nil { + t.Errorf("reading tarball: %v", err) + } + // Make sure it has the correct checksum + checksum := md5.Sum(contents) + remoteChecksum, err := ioutil.ReadFile(download.PreloadChecksumPath(constants.DefaultKubernetesVersion)) + if err != nil { + t.Errorf("reading checksum file: %v", err) + } + if string(remoteChecksum) != string(checksum[:]) { + t.Errorf("checksum of %s does not match remote checksum (%s != %s)", tarball, string(remoteChecksum), string(checksum[:])) + } + + // Make sure this image exists in the docker daemon + ref, err := name.ParseReference(kic.BaseImage) + if err != nil { + t.Errorf("parsing reference failed: %v", err) + } + if _, err := daemon.Image(ref); err != nil { + t.Errorf("expected image does not exist in local daemon: %v", err) + } +} + +func runningDockerDriver(startArgs []string) bool { + for _, s := range startArgs { + if s == "--driver=docker" { + return true + } + } + return false +} diff --git a/test/integration/functional_test.go b/test/integration/functional_test.go index 2e64ef4d05..8445aa364a 100644 --- a/test/integration/functional_test.go +++ b/test/integration/functional_test.go @@ -28,6 +28,7 @@ import ( "net/url" "os" "os/exec" + "path" "path/filepath" "regexp" "runtime" @@ -57,10 +58,17 @@ func TestFunctional(t *testing.T) { profile := UniqueProfileName("functional") ctx, cancel := context.WithTimeout(context.Background(), Minutes(40)) defer func() { + if !*cleanup { + return + } p := localSyncTestPath() if err := os.Remove(p); err != nil { t.Logf("unable to remove %s: %v", p, err) } + p = localTestCertPath() + if err := os.Remove(p); err != nil { + t.Logf("unable to remove %s: %v", p, err) + } CleanupWithLogs(t, profile, cancel) }() @@ -110,6 +118,7 @@ func TestFunctional(t *testing.T) { {"SSHCmd", validateSSHCmd}, {"MySQL", validateMySQL}, {"FileSync", validateFileSync}, + {"CertSync", validateCertSync}, {"UpdateContextCmd", validateUpdateContextCmd}, {"DockerEnv", validateDockerEnv}, {"NodeLabels", validateNodeLabels}, @@ -731,6 +740,16 @@ func localSyncTestPath() string { return filepath.Join(localpath.MiniPath(), "/files", vmSyncTestPath()) } +// testCert is name of the test certificate installed +func testCert() string { + return fmt.Sprintf("%d.pem", os.Getpid()) +} + +// localTestCertPath is where the test file will be synced into the VM +func localTestCertPath() string { + return filepath.Join(localpath.MiniPath(), "/certs", testCert()) +} + // Copy extra file into minikube home folder for file sync test func setupFileSync(ctx context.Context, t *testing.T, profile string) { p := localSyncTestPath() @@ -739,6 +758,11 @@ func setupFileSync(ctx context.Context, t *testing.T, profile string) { if err != nil { t.Fatalf("copy: %v", err) } + + err = copy.Copy("./testdata/minikube_test.pem", localTestCertPath()) + if err != nil { + t.Fatalf("copy: %v", err) + } } // validateFileSync to check existence of the test file @@ -766,6 +790,39 @@ func validateFileSync(ctx context.Context, t *testing.T, profile string) { } } +// validateCertSync to check existence of the test certificate +func validateCertSync(ctx context.Context, t *testing.T, profile string) { + if NoneDriver() { + t.Skipf("skipping: ssh unsupported by none") + } + + want, err := ioutil.ReadFile("./testdata/minikube_test.pem") + if err != nil { + t.Errorf("test file not found: %v", err) + } + + // Check both the installed & reference certs (they should be symlinked) + paths := []string{ + path.Join("/etc/ssl/certs", testCert()), + path.Join("/usr/share/ca-certificates", testCert()), + // hashed path generated by: 'openssl x509 -hash -noout -in testCert()' + "/etc/ssl/certs/51391683.0", + } + for _, vp := range paths { + t.Logf("Checking for existence of %s within VM", vp) + rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", fmt.Sprintf("cat %s", vp))) + if err != nil { + t.Errorf("%s failed: %v", rr.Args, err) + } + + // Strip carriage returned by ssh + got := strings.Replace(rr.Stdout.String(), "\r", "", -1) + if diff := cmp.Diff(string(want), got); diff != "" { + t.Errorf("minikube_test.pem -> %s mismatch (-want +got):\n%s", vp, diff) + } + } +} + // validateUpdateContextCmd asserts basic "update-context" command functionality func validateUpdateContextCmd(ctx context.Context, t *testing.T, profile string) { rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "update-context", "--alsologtostderr", "-v=2")) diff --git a/test/integration/main.go b/test/integration/main.go index 3885d338cd..33c5e09618 100644 --- a/test/integration/main.go +++ b/test/integration/main.go @@ -61,12 +61,12 @@ func Target() string { // NoneDriver returns whether or not this test is using the none driver func NoneDriver() bool { - return strings.Contains(*startArgs, "--vm-driver=none") + return strings.Contains(*startArgs, "--driver=none") } // HyperVDriver returns whether or not this test is using the Hyper-V driver func HyperVDriver() bool { - return strings.Contains(*startArgs, "--vm-driver=hyperv") + return strings.Contains(*startArgs, "--driver=hyperv") } // ExpectedDefaultDriver returns the expected default driver, if any diff --git a/test/integration/testdata/minikube_test.pem b/test/integration/testdata/minikube_test.pem new file mode 100644 index 0000000000..5f022a853e --- /dev/null +++ b/test/integration/testdata/minikube_test.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDsDCCApgCCQD5n0OIsOYIjDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UEBhMC +VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x +ETAPBgNVBAoMCG1pbmlrdWJlMRYwFAYDVQQLDA1QYXJ0eSBQYXJyb3RzMREwDwYD +VQQDDAhtaW5pa3ViZTEfMB0GCSqGSIb3DQEJARYQbWluaWt1YmVAY25jZi5pbzAe +Fw0yMDAzMDQyMTU2MjZaFw0yMTAzMDQyMTU2MjZaMIGZMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzERMA8G +A1UECgwIbWluaWt1YmUxFjAUBgNVBAsMDVBhcnR5IFBhcnJvdHMxETAPBgNVBAMM +CG1pbmlrdWJlMR8wHQYJKoZIhvcNAQkBFhBtaW5pa3ViZUBjbmNmLmlvMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/qVMQ/234ul5yWI1yaHvV4pZ5Ffy +M0bSMjzZUwlsvzerXzF3WrdpeZs5GzBNBWL/Db9KziGHCtfX9j5okJqPvB2lxdL5 +d5hFIYSORSemYLX2kdlnlykY5fzmFLKIUO9xXs0YNF4JUMEBgGK6n/BdLvXDUULZ +26QOKs6+iH7TAL4RtozxQ8YXKQArdmpeAvxy2PSZGvVk1htKtyuKQsiFqH3oRleK +3mljXfC5LsoIJHqd/8lAsckH87+IfwYnJ1CNJM2gueaCf+HmudVrvXfHaszh1Wh1 +9HKPE95Azi6CKoBGlRGFxt8UR72YIcTjC/lYxzbHeCpU7RCiXfsC0iMTlQIDAQAB +MA0GCSqGSIb3DQEBCwUAA4IBAQBhsKnghyBki4NOnK5gHm7ow+7S+xvkjJhXBQ6i +/xQD4/GCZ1tH5iFHXmo+bt4jB9hvKLyN5M5a8TlDwwqTLIoPDQJh37UpSCwbY/6z +nE2aP3N2ue1/DeY60tgAh1c1uJDMeTiFbalJqSkneaHpNfvEQhUORFoN4yQSVEYg ++T9mzTAWQ55TeBgbRevmA25nXHdPAae1MvJWDeG+aJfhq1I2hCwaitJ3iSwgn2ew +637It/aBkMLhsCKTHxlXDGUX401ddbc0ZiC308cyMbis3iBeh4RBjkFxP8eIWFmK +sos/dyqdua742L1cOKYFbLJfjA1VyxJQUxQvWKkbaq0xi7ao +-----END CERTIFICATE----- diff --git a/translations/de.json b/translations/de.json index 441d5f3c70..aad33a4c04 100644 --- a/translations/de.json +++ b/translations/de.json @@ -2,7 +2,7 @@ "\"The '{{.minikube_addon}}' addon is disabled": "", "\"{{.name}}\" profile does not exist": "", "\"{{.name}}\" profile does not exist, trying anyways.": "", - "\"{{.profile_name}}\" VM does not exist, nothing to stop": "", + "\"{{.profile_name}}\" does not exist, nothing to stop": "", "\"{{.profile_name}}\" host does not exist, unable to show an IP": "", "\"{{.profile_name}}\" stopped.": "", "'none' driver does not support 'minikube docker-env' command": "", @@ -26,7 +26,7 @@ "Add an image to local cache.": "", "Add machine IP to NO_PROXY environment variable": "", "Add or delete an image from the local cache.": "", - "Adding node {{.name}} to cluster {{.profile}}": "", + "Adding node {{.name}} to cluster {{.cluster}}": "", "Additional help topics": "", "Additional mount options, such as cache=fscache": "", "Adds a node to the given cluster config, and starts it.": "", @@ -44,6 +44,8 @@ "Automatically selected the {{.driver}} driver. Other choices: {{.alternates}}": "", "Available Commands": "", "Basic Commands:": "", + "Because you are using docker driver on Mac, the terminal needs to be open to run it.": "", + "Bind Address: {{.Address}}": "", "Block until the apiserver is servicing API requests": "", "Cannot find directory {{.path}} for mount": "", "Cannot use both --output and --format options": "", @@ -60,15 +62,13 @@ "Configuring local host environment ...": "", "Confirm that you have a working internet connection and that your VM has not run out of resources by using: 'minikube logs'": "", "Confirm that you have supplied the correct value to --hyperv-virtual-switch using the 'Get-VMSwitch' command": "", - "Could not get profile flag": "", "Could not process error from failed deletion": "", "Could not process errors from failed deletion": "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn.": "Ländercode des zu verwendenden Image Mirror. Lassen Sie dieses Feld leer, um den globalen zu verwenden. Nutzer vom chinesischen Festland stellen cn ein.", - "Created a new profile : {{.profile_name}}": "", - "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", - "Creating a new profile failed": "", + "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", "Creating mount {{.name}} ...": "Bereitstellung {{.name}} wird erstellt...", "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "", + "DEPRECATED, use `driver` instead.": "", "Default group id used for the mount": "", "Default user id used for the mount": "", "Delete an image from the local cache.": "", @@ -77,6 +77,7 @@ "Deletes a local kubernetes cluster. This command deletes the VM, and removes all associated files.": "Damit wird ein lokaler Kubernetes-Cluster gelöscht. Mit diesem Befehl wird die VM entfernt und alle zugehörigen Dateien gelöscht.", "Deletes a node from a cluster.": "", "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "{{.profile_name}}\" in {{.driver_name}} wird gelöscht...", + "Deleting node {{.name}} from cluster {{.cluster}}": "", "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)": "Deaktivieren Sie die Überprüfung der Verfügbarkeit der Hardwarevirtualisierung vor dem Starten der VM (nur Virtualbox-Treiber)", "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list": "", @@ -97,6 +98,7 @@ "Download complete!": "Download abgeschlossen!", "Downloading VM boot image ...": "", "Downloading driver {{.driver}}:": "", + "Downloading preloaded images tarball for k8s {{.version}} ...": "", "Downloading {{.name}} {{.version}}": "", "ERROR creating `registry-creds-acr` secret": "", "ERROR creating `registry-creds-dpr` secret": "", @@ -138,7 +140,7 @@ "Error getting host IP": "", "Error getting host status": "", "Error getting machine logs": "", - "Error getting profiles to delete": "", + "Error getting port binding for '{{.driver_name}} driver: {{.error}}": "", "Error getting service status": "", "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "", "Error getting ssh client": "", @@ -170,6 +172,7 @@ "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images to tar": "", + "Failed to cache kubectl": "", "Failed to change permissions for {{.minikube_dir_path}}: {{.error}}": "Fehler beim Ändern der Berechtigungen für {{.minikube_dir_path}}: {{.error}}", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", @@ -177,7 +180,7 @@ "Failed to delete cluster: {{.error}}__1": "Fehler beim Löschen des Clusters: {{.error}}", "Failed to delete images": "", "Failed to delete images from config": "", - "Failed to download kubectl": "", + "Failed to delete node {{.name}}": "", "Failed to enable container runtime": "", "Failed to generate config": "", "Failed to get bootstrapper": "", @@ -194,6 +197,8 @@ "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.": "", "Failed to setup certs": "", "Failed to setup kubeconfig": "", + "Failed to start node {{.name}}": "", + "Failed to stop node {{.name}}": "", "Failed to update cluster": "", "Failed to update config": "", "Failed unmount: {{.error}}": "", @@ -228,12 +233,13 @@ "If set, pause all namespaces": "", "If set, unpause all namespaces": "", "If the above advice does not help, please let us know:": "", + "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.": "", "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --vm-driver=none.": "Wenn true, speichern Sie Docker-Images für den aktuellen Bootstrapper zwischen und laden Sie sie auf den Computer. Immer falsch mit --vm-driver = none.", "If true, only download and cache files for later use - don't install or start anything.": "Wenn true, laden Sie nur Dateien für die spätere Verwendung herunter und speichern Sie sie – installieren oder starten Sie nichts.", "If true, the added node will be marked for work. Defaults to true.": "", "If true, the node added will also be a control plane in addition to a worker.": "", "If using the none driver, ensure that systemctl is installed": "", - "If you are running minikube within a VM, consider using --vm-driver=none:": "", + "If you are running minikube within a VM, consider using --driver=none:": "", "Images Commands:": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "Unsichere Docker-Registrys, die an den Docker-Daemon übergeben werden. Der CIDR-Bereich des Standarddienstes wird automatisch hinzugefügt.", @@ -275,6 +281,7 @@ "No minikube profile was found. You can create one using `minikube start`.": "", "Node may be unable to resolve external DNS records": "", "Node operations": "", + "Node {{.name}} was successfully deleted.": "", "None of the known repositories in your location are accessible. Using {{.image_repository_name}} as fallback.": "Keines der bekannten Repositories an Ihrem Standort ist zugänglich. {{.image_repository_name}} wird als Fallback verwendet.", "None of the known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "Keines der bekannten Repositories ist zugänglich. Erwägen Sie, ein alternatives Image-Repository mit der Kennzeichnung --image-repository anzugeben", "Not passing {{.name}}={{.value}} to docker env.": "", @@ -369,13 +376,16 @@ "Specify the mount filesystem type (supported types: 9p)": "", "Starting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", "Starting node": "", + "Starting tunnel for service {{.service}}.": "", "Starts a local kubernetes cluster": "Startet einen lokalen Kubernetes-Cluster", "Starts a node.": "", "Starts an existing stopped node in a cluster.": "", "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Stopping tunnel for service {{.service}}.": "", "Stops a local kubernetes cluster running in Virtualbox. This command stops the VM\nitself, leaving all files intact. The cluster can be started again with the \"start\" command.": "", "Stops a node in a cluster.": "", "Stops a running local kubernetes cluster": "", + "Successfully added {{.name}} to {{.cluster}}!": "", "Successfully deleted all profiles": "", "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "", "Successfully powered off Hyper-V. minikube driver -- {{.driver}}": "", @@ -383,17 +393,17 @@ "Suggestion: {{.advice}}": "", "Suggestion: {{.fix}}": "", "Target directory {{.path}} must be an absolute path": "", + "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}": "Der Treiber \"{{.driver_name}}\" benötigt Root-Rechte. Führen Sie minikube aus mit 'sudo minikube --vm-driver = {{. Driver_name}}.", - "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver should not be used with root privileges.": "", "The \"{{.name}}\" cluster has been deleted.": "Der Cluster \"{{.name}}\" wurde gelöscht.", "The \"{{.name}}\" cluster has been deleted.__1": "Der Cluster \"{{.name}}\" wurde gelöscht.", - "The 'none' driver does not respect the --cpus flag": "", - "The 'none' driver does not respect the --memory flag": "", - "The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "Der Treiber \"Keine\" bietet eine eingeschränkte Isolation und beeinträchtigt möglicherweise Sicherheit und Zuverlässigkeit des Systems.", "The '{{.addonName}}' addon is enabled": "", "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "", + "The '{{.name}} driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", + "The '{{.name}}' driver does not respect the --cpus flag": "", + "The '{{.name}}' driver does not respect the --memory flag": "", "The CIDR to be used for service cluster IPs.": "Die CIDR, die für Service-Cluster-IPs verwendet werden soll.", "The CIDR to be used for the minikube VM (virtualbox driver only)": "Die CIDR, die für die minikube-VM verwendet werden soll (nur Virtualbox-Treiber)", "The KVM QEMU connection URI. (kvm2 driver only)": "Der KVM-QEMU-Verbindungs-URI. (Nur kvm2-Treiber)", @@ -426,11 +436,13 @@ "The name of the network plugin.": "", "The name of the node to add.": "", "The name of the node to delete": "", + "The name of the node to start": "", "The number of bytes to use for 9p packet payload": "", "The output format. One of 'json', 'table'": "", "The path on the file system where the docs in markdown need to be saved": "", "The podman service within '{{.profile}}' is not active": "", "The service namespace": "", + "The service {{.service}} requires privileged ports to be exposed: {{.ports}}": "", "The services namespace": "", "The time interval for each check that wait performs in seconds": "", "The value passed to --format is invalid": "", @@ -449,14 +461,14 @@ "To connect to this cluster, use: kubectl --context={{.name}}__1": "Verwenden Sie zum Herstellen einer Verbindung zu diesem Cluster: kubectl --context = {{.name}}", "To connect to this cluster, use: kubectl --context={{.profile_name}}": "", "To disable this notice, run: 'minikube config set WantUpdateNotification false'\\n": "", - "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --vm-driver={{.old_driver}}'": "", + "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --driver={{.old_driver}}'": "", "To see addons list for other profiles use: `minikube addons -p name list`": "", "To start minikube with HyperV Powershell must be in your PATH`": "", "To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:": "Möglicherweise müssen Sie Kubectl- oder minikube-Befehle verschieben, um sie als eigenen Nutzer zu verwenden. Um beispielsweise Ihre eigenen Einstellungen zu überschreiben, führen Sie aus:", "Troubleshooting Commands:": "", "Trying to delete invalid profile {{.profile}}": "", "Unable to bind flags": "", - "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/": "", + "Unable to determine a default driver to use. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/": "", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", "Unable to generate docs": "", @@ -494,6 +506,9 @@ "Usage: minikube delete": "", "Usage: minikube delete --all --purge": "", "Usage: minikube node [add|start|stop|delete]": "", + "Usage: minikube node delete [name]": "", + "Usage: minikube node start [name]": "", + "Usage: minikube node stop [name]": "", "Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "", "Use 'kubect get po -A' to find the correct and namespace name": "", "Use -A to specify all namespaces": "", @@ -542,7 +557,7 @@ "bash completion failed": "", "call with cleanup=true to remove old tunnels": "", "command runner": "", - "config modifies minikube config files using subcommands like \"minikube config set vm-driver kvm\"\nConfigurable fields:\\n\\n": "", + "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields:\\n\\n": "", "config view failed": "", "creating api client": "", "dashboard service is not running: {{.error}}": "", @@ -552,10 +567,13 @@ "enable failed": "", "error creating clientset": "", "error creating machine client": "", + "error getting ssh port": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", + "error stopping tunnel": "", "failed to open browser: {{.error}}": "", "if true, will embed the certs in kubeconfig.": "", + "if you want to create a profile you can by this command: minikube start -p {{.profile_name}}": "", "kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "", "kubectl and minikube configuration will be stored in {{.home_folder}}": "Konfiguration von Kubectl und minikube wird in {{.home_folder}} gespeichert", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", @@ -574,12 +592,12 @@ "mkcmp is used to compare performance of two minikube binaries": "", "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "", - "name is required": "", "namespaces to pause": "", "namespaces to unpause": "", "not enough arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", "pause containers": "", "profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`": "", + "profile {{.name}} is not running.": "", "reload cached images.": "", "reloads images previously added using the 'cache add' subcommand": "", "retrieving node": "", @@ -606,7 +624,6 @@ "usage: minikube addons open ADDON_NAME": "", "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", - "usage: minikube delete --all": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", "zsh completion failed": "", "{{.driver}} does not appear to be installed": "", @@ -617,7 +634,6 @@ "{{.name}} cluster does not exist": "", "{{.name}} has no available configuration options": "", "{{.name}} is already running": "", - "{{.name}} is already stopped": "", "{{.name}} was successfully configured": "", "{{.name}}\" profile does not exist": "Profil \"{{.name}}\" existiert nicht", "{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster": "", diff --git a/translations/es.json b/translations/es.json index d16163072b..9ae4651839 100644 --- a/translations/es.json +++ b/translations/es.json @@ -2,7 +2,7 @@ "\"The '{{.minikube_addon}}' addon is disabled": "", "\"{{.name}}\" profile does not exist": "El perfil \"{{.name}}\" no existe", "\"{{.name}}\" profile does not exist, trying anyways.": "", - "\"{{.profile_name}}\" VM does not exist, nothing to stop": "", + "\"{{.profile_name}}\" does not exist, nothing to stop": "", "\"{{.profile_name}}\" host does not exist, unable to show an IP": "", "\"{{.profile_name}}\" stopped.": "", "'none' driver does not support 'minikube docker-env' command": "", @@ -26,7 +26,7 @@ "Add an image to local cache.": "", "Add machine IP to NO_PROXY environment variable": "", "Add or delete an image from the local cache.": "", - "Adding node {{.name}} to cluster {{.profile}}": "", + "Adding node {{.name}} to cluster {{.cluster}}": "", "Additional help topics": "", "Additional mount options, such as cache=fscache": "", "Adds a node to the given cluster config, and starts it.": "", @@ -44,6 +44,8 @@ "Automatically selected the {{.driver}} driver. Other choices: {{.alternates}}": "", "Available Commands": "", "Basic Commands:": "", + "Because you are using docker driver on Mac, the terminal needs to be open to run it.": "", + "Bind Address: {{.Address}}": "", "Block until the apiserver is servicing API requests": "", "Cannot find directory {{.path}} for mount": "", "Cannot use both --output and --format options": "", @@ -60,15 +62,13 @@ "Configuring local host environment ...": "", "Confirm that you have a working internet connection and that your VM has not run out of resources by using: 'minikube logs'": "", "Confirm that you have supplied the correct value to --hyperv-virtual-switch using the 'Get-VMSwitch' command": "", - "Could not get profile flag": "", "Could not process error from failed deletion": "", "Could not process errors from failed deletion": "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn.": "Código de país de la réplica de imagen que quieras utilizar. Déjalo en blanco para usar el valor global. Los usuarios de China continental deben definirlo como cn.", - "Created a new profile : {{.profile_name}}": "", - "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", - "Creating a new profile failed": "", + "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", "Creating mount {{.name}} ...": "Creando la activación {{.name}}...", "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "", + "DEPRECATED, use `driver` instead.": "", "Default group id used for the mount": "", "Default user id used for the mount": "", "Delete an image from the local cache.": "", @@ -77,6 +77,7 @@ "Deletes a local kubernetes cluster. This command deletes the VM, and removes all associated files.": "Elimina un clúster local de Kubernetes. Este comando borra la VM y todos los archivos asociados.", "Deletes a node from a cluster.": "", "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "Eliminando \"{{.profile_name}}\" en {{.driver_name}}...", + "Deleting node {{.name}} from cluster {{.cluster}}": "", "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)": "Permite inhabilitar la comprobación de disponibilidad de la virtualización de hardware antes de iniciar la VM (solo con el controlador de Virtualbox)", "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list": "", @@ -97,6 +98,7 @@ "Download complete!": "Se ha completado la descarga", "Downloading VM boot image ...": "", "Downloading driver {{.driver}}:": "", + "Downloading preloaded images tarball for k8s {{.version}} ...": "", "Downloading {{.name}} {{.version}}": "", "ERROR creating `registry-creds-acr` secret": "", "ERROR creating `registry-creds-dpr` secret": "", @@ -138,7 +140,7 @@ "Error getting host IP": "", "Error getting host status": "", "Error getting machine logs": "", - "Error getting profiles to delete": "", + "Error getting port binding for '{{.driver_name}} driver: {{.error}}": "", "Error getting service status": "", "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "", "Error getting ssh client": "", @@ -170,6 +172,7 @@ "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images to tar": "", + "Failed to cache kubectl": "", "Failed to change permissions for {{.minikube_dir_path}}: {{.error}}": "No se han podido cambiar los permisos de {{.minikube_dir_path}}: {{.error}}", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", @@ -177,7 +180,7 @@ "Failed to delete cluster: {{.error}}__1": "No se ha podido eliminar el clúster: {{.error}}", "Failed to delete images": "", "Failed to delete images from config": "", - "Failed to download kubectl": "", + "Failed to delete node {{.name}}": "", "Failed to enable container runtime": "", "Failed to generate config": "", "Failed to get bootstrapper": "", @@ -194,6 +197,8 @@ "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.": "", "Failed to setup certs": "", "Failed to setup kubeconfig": "", + "Failed to start node {{.name}}": "", + "Failed to stop node {{.name}}": "", "Failed to update cluster": "", "Failed to update config": "", "Failed unmount: {{.error}}": "", @@ -228,12 +233,13 @@ "If set, pause all namespaces": "", "If set, unpause all namespaces": "", "If the above advice does not help, please let us know:": "", + "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.": "", "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --vm-driver=none.": "Si el valor es \"true\", las imágenes de Docker del programa previo actual se almacenan en caché y se cargan en la máquina. Siempre es \"false\" si se especifica --vm-driver=none.", "If true, only download and cache files for later use - don't install or start anything.": "Si el valor es \"true\", los archivos solo se descargan y almacenan en caché (no se instala ni inicia nada).", "If true, the added node will be marked for work. Defaults to true.": "", "If true, the node added will also be a control plane in addition to a worker.": "", "If using the none driver, ensure that systemctl is installed": "", - "If you are running minikube within a VM, consider using --vm-driver=none:": "", + "If you are running minikube within a VM, consider using --driver=none:": "", "Images Commands:": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "Registros de Docker que no son seguros y que se transferirán al daemon de Docker. Se añadirá automáticamente el intervalo CIDR de servicio predeterminado.", @@ -275,6 +281,7 @@ "No minikube profile was found. You can create one using `minikube start`.": "", "Node may be unable to resolve external DNS records": "", "Node operations": "", + "Node {{.name}} was successfully deleted.": "", "None of the known repositories in your location are accessible. Using {{.image_repository_name}} as fallback.": "No se puede acceder a ninguno de los repositorios conocidos de tu ubicación. Se utilizará {{.image_repository_name}} como alternativa.", "None of the known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "No se puede acceder a ninguno de los repositorios conocidos. Plantéate indicar un repositorio de imágenes alternativo con la marca --image-repository.", "Not passing {{.name}}={{.value}} to docker env.": "", @@ -369,13 +376,16 @@ "Specify the mount filesystem type (supported types: 9p)": "", "Starting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", "Starting node": "", + "Starting tunnel for service {{.service}}.": "", "Starts a local kubernetes cluster": "Inicia un clúster de Kubernetes local", "Starts a node.": "", "Starts an existing stopped node in a cluster.": "", "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Stopping tunnel for service {{.service}}.": "", "Stops a local kubernetes cluster running in Virtualbox. This command stops the VM\nitself, leaving all files intact. The cluster can be started again with the \"start\" command.": "", "Stops a node in a cluster.": "", "Stops a running local kubernetes cluster": "", + "Successfully added {{.name}} to {{.cluster}}!": "", "Successfully deleted all profiles": "", "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "", "Successfully powered off Hyper-V. minikube driver -- {{.driver}}": "", @@ -383,17 +393,17 @@ "Suggestion: {{.advice}}": "", "Suggestion: {{.fix}}": "", "Target directory {{.path}} must be an absolute path": "", + "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}": "El controlador \"{{.driver_name}}\" requiere privilegios de raíz. Ejecuta minikube mediante sudo minikube --vm-driver={{.driver_name}}", - "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver should not be used with root privileges.": "", "The \"{{.name}}\" cluster has been deleted.": "Se ha eliminado el clúster \"{{.name}}\".", "The \"{{.name}}\" cluster has been deleted.__1": "Se ha eliminado el clúster \"{{.name}}\".", - "The 'none' driver does not respect the --cpus flag": "", - "The 'none' driver does not respect the --memory flag": "", - "The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "La opción de controlador \"none\" proporciona un aislamiento limitado y puede reducir la seguridad y la fiabilidad del sistema.", "The '{{.addonName}}' addon is enabled": "", "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "", + "The '{{.name}} driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", + "The '{{.name}}' driver does not respect the --cpus flag": "", + "The '{{.name}}' driver does not respect the --memory flag": "", "The CIDR to be used for service cluster IPs.": "El CIDR de las IP del clúster de servicio.", "The CIDR to be used for the minikube VM (virtualbox driver only)": "El CIDR de la VM de minikube (solo con el controlador de Virtualbox)", "The KVM QEMU connection URI. (kvm2 driver only)": "El URI de la conexión de QEMU de la KVM (solo con el controlador de kvm2).", @@ -426,11 +436,13 @@ "The name of the network plugin.": "", "The name of the node to add.": "", "The name of the node to delete": "", + "The name of the node to start": "", "The number of bytes to use for 9p packet payload": "", "The output format. One of 'json', 'table'": "", "The path on the file system where the docs in markdown need to be saved": "", "The podman service within '{{.profile}}' is not active": "", "The service namespace": "", + "The service {{.service}} requires privileged ports to be exposed: {{.ports}}": "", "The services namespace": "", "The time interval for each check that wait performs in seconds": "", "The value passed to --format is invalid": "", @@ -449,14 +461,14 @@ "To connect to this cluster, use: kubectl --context={{.name}}__1": "Para conectarte a este clúster, usa: kubectl --context={{.name}}", "To connect to this cluster, use: kubectl --context={{.profile_name}}": "", "To disable this notice, run: 'minikube config set WantUpdateNotification false'\\n": "", - "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --vm-driver={{.old_driver}}'": "", + "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --driver={{.old_driver}}'": "", "To see addons list for other profiles use: `minikube addons -p name list`": "", "To start minikube with HyperV Powershell must be in your PATH`": "", "To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:": "Para usar comandos de kubectl o minikube como tu propio usuario, puede que debas reubicarlos. Por ejemplo, para sobrescribir tu configuración, ejecuta:", "Troubleshooting Commands:": "", "Trying to delete invalid profile {{.profile}}": "", "Unable to bind flags": "", - "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/": "", + "Unable to determine a default driver to use. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/": "", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", "Unable to generate docs": "", @@ -494,6 +506,9 @@ "Usage: minikube delete": "", "Usage: minikube delete --all --purge": "", "Usage: minikube node [add|start|stop|delete]": "", + "Usage: minikube node delete [name]": "", + "Usage: minikube node start [name]": "", + "Usage: minikube node stop [name]": "", "Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "", "Use 'kubect get po -A' to find the correct and namespace name": "", "Use -A to specify all namespaces": "", @@ -542,7 +557,7 @@ "bash completion failed": "", "call with cleanup=true to remove old tunnels": "", "command runner": "", - "config modifies minikube config files using subcommands like \"minikube config set vm-driver kvm\"\nConfigurable fields:\\n\\n": "", + "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields:\\n\\n": "", "config view failed": "", "creating api client": "", "dashboard service is not running: {{.error}}": "", @@ -552,10 +567,13 @@ "enable failed": "", "error creating clientset": "", "error creating machine client": "", + "error getting ssh port": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", + "error stopping tunnel": "", "failed to open browser: {{.error}}": "", "if true, will embed the certs in kubeconfig.": "", + "if you want to create a profile you can by this command: minikube start -p {{.profile_name}}": "", "kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "", "kubectl and minikube configuration will be stored in {{.home_folder}}": "La configuración de kubectl y de minikube se almacenará en {{.home_folder}}", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", @@ -574,12 +592,12 @@ "mkcmp is used to compare performance of two minikube binaries": "", "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "", - "name is required": "", "namespaces to pause": "", "namespaces to unpause": "", "not enough arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", "pause containers": "", "profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`": "", + "profile {{.name}} is not running.": "", "reload cached images.": "", "reloads images previously added using the 'cache add' subcommand": "", "retrieving node": "", @@ -606,7 +624,6 @@ "usage: minikube addons open ADDON_NAME": "", "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", - "usage: minikube delete --all": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", "zsh completion failed": "", "{{.driver}} does not appear to be installed": "", @@ -617,7 +634,6 @@ "{{.name}} cluster does not exist": "", "{{.name}} has no available configuration options": "", "{{.name}} is already running": "", - "{{.name}} is already stopped": "", "{{.name}} was successfully configured": "", "{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster": "", "{{.prefix}}minikube {{.version}} on {{.platform}}": "{{.prefix}}minikube {{.version}} en {{.platform}}", diff --git a/translations/fr.json b/translations/fr.json index 94f3b3185c..952d0e1992 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -2,7 +2,7 @@ "\"The '{{.minikube_addon}}' addon is disabled": "", "\"{{.name}}\" profile does not exist": "Le profil \"{{.name}}\" n'existe pas.", "\"{{.name}}\" profile does not exist, trying anyways.": "", - "\"{{.profile_name}}\" VM does not exist, nothing to stop": "", + "\"{{.profile_name}}\" does not exist, nothing to stop": "", "\"{{.profile_name}}\" host does not exist, unable to show an IP": "", "\"{{.profile_name}}\" stopped.": "\"{{.profile_name}}\" est arrêté.", "'none' driver does not support 'minikube docker-env' command": "", @@ -26,7 +26,7 @@ "Add an image to local cache.": "", "Add machine IP to NO_PROXY environment variable": "", "Add or delete an image from the local cache.": "", - "Adding node {{.name}} to cluster {{.profile}}": "", + "Adding node {{.name}} to cluster {{.cluster}}": "", "Additional help topics": "", "Additional mount options, such as cache=fscache": "", "Adds a node to the given cluster config, and starts it.": "", @@ -44,6 +44,8 @@ "Automatically selected the {{.driver}} driver. Other choices: {{.alternates}}": "", "Available Commands": "", "Basic Commands:": "", + "Because you are using docker driver on Mac, the terminal needs to be open to run it.": "", + "Bind Address: {{.Address}}": "", "Block until the apiserver is servicing API requests": "", "Cannot find directory {{.path}} for mount": "", "Cannot use both --output and --format options": "", @@ -61,15 +63,13 @@ "Configuring local host environment ...": "", "Confirm that you have a working internet connection and that your VM has not run out of resources by using: 'minikube logs'": "", "Confirm that you have supplied the correct value to --hyperv-virtual-switch using the 'Get-VMSwitch' command": "", - "Could not get profile flag": "", "Could not process error from failed deletion": "", "Could not process errors from failed deletion": "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn.": "Code pays du miroir d'images à utiliser. Laissez ce paramètre vide pour utiliser le miroir international. Pour les utilisateurs situés en Chine continentale, définissez sa valeur sur \"cn\".", - "Created a new profile : {{.profile_name}}": "", - "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", - "Creating a new profile failed": "", + "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", "Creating mount {{.name}} ...": "Création de l'installation {{.name}}…", "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "Création d'une VM {{.driver_name}} (CPUs={{.number_of_cpus}}, Mémoire={{.memory_size}}MB, Disque={{.disk_size}}MB)...", + "DEPRECATED, use `driver` instead.": "", "Default group id used for the mount": "", "Default user id used for the mount": "", "Delete an image from the local cache.": "", @@ -78,6 +78,7 @@ "Deletes a local kubernetes cluster. This command deletes the VM, and removes all associated files.": "Supprime le cluster Kubernetes local. Cette commande supprime la VM ainsi que tous les fichiers associés.", "Deletes a node from a cluster.": "", "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "Suppression de \"{{.profile_name}}\" dans {{.driver_name}}...", + "Deleting node {{.name}} from cluster {{.cluster}}": "", "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)": "Désactive la vérification de la disponibilité de la virtualisation du matériel avant le démarrage de la VM (pilote virtualbox uniquement).", "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list": "", @@ -97,6 +98,7 @@ "Download complete!": "Téléchargement terminé !", "Downloading VM boot image ...": "", "Downloading driver {{.driver}}:": "", + "Downloading preloaded images tarball for k8s {{.version}} ...": "", "Downloading {{.name}} {{.version}}": "", "ERROR creating `registry-creds-acr` secret": "", "ERROR creating `registry-creds-dpr` secret": "", @@ -138,7 +140,7 @@ "Error getting host IP": "", "Error getting host status": "", "Error getting machine logs": "", - "Error getting profiles to delete": "", + "Error getting port binding for '{{.driver_name}} driver: {{.error}}": "", "Error getting service status": "", "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "", "Error getting ssh client": "", @@ -170,6 +172,7 @@ "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images to tar": "", + "Failed to cache kubectl": "", "Failed to change permissions for {{.minikube_dir_path}}: {{.error}}": "Échec de la modification des autorisations pour {{.minikube_dir_path}} : {{.error}}", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", @@ -177,7 +180,7 @@ "Failed to delete cluster: {{.error}}__1": "Échec de la suppression du cluster : {{.error}}", "Failed to delete images": "", "Failed to delete images from config": "", - "Failed to download kubectl": "", + "Failed to delete node {{.name}}": "", "Failed to enable container runtime": "", "Failed to generate config": "", "Failed to get bootstrapper": "", @@ -194,6 +197,8 @@ "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.": "", "Failed to setup certs": "", "Failed to setup kubeconfig": "", + "Failed to start node {{.name}}": "", + "Failed to stop node {{.name}}": "", "Failed to update cluster": "", "Failed to update config": "", "Failed unmount: {{.error}}": "", @@ -228,12 +233,13 @@ "If set, pause all namespaces": "", "If set, unpause all namespaces": "", "If the above advice does not help, please let us know:": "", + "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.": "", "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --vm-driver=none.": "Si la valeur est \"true\", mettez les images Docker en cache pour l'amorceur actuel et chargez-les dans la machine. La valeur est toujours \"false\" avec --vm-driver=none.", "If true, only download and cache files for later use - don't install or start anything.": "Si la valeur est \"true\", téléchargez les fichiers et mettez-les en cache uniquement pour une utilisation future. Ne lancez pas d'installation et ne commencez aucun processus.", "If true, the added node will be marked for work. Defaults to true.": "", "If true, the node added will also be a control plane in addition to a worker.": "", "If using the none driver, ensure that systemctl is installed": "", - "If you are running minikube within a VM, consider using --vm-driver=none:": "", + "If you are running minikube within a VM, consider using --driver=none:": "", "Images Commands:": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "Registres Docker non sécurisés à transmettre au daemon Docker. La plage CIDR par défaut du service sera ajoutée automatiquement.", @@ -275,6 +281,7 @@ "No minikube profile was found. You can create one using `minikube start`.": "", "Node may be unable to resolve external DNS records": "", "Node operations": "", + "Node {{.name}} was successfully deleted.": "", "None of the known repositories in your location are accessible. Using {{.image_repository_name}} as fallback.": "Aucun dépôt connu dans votre emplacement n'est accessible. {{.image_repository_name}} est utilisé comme dépôt de remplacement.", "None of the known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "Aucun dépôt connu n'est accessible. Pensez à spécifier un autre dépôt d'images à l'aide de l'indicateur \"--image-repository\".", "Not passing {{.name}}={{.value}} to docker env.": "", @@ -370,13 +377,16 @@ "Specify the mount filesystem type (supported types: 9p)": "", "Starting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", "Starting node": "", + "Starting tunnel for service {{.service}}.": "", "Starts a local kubernetes cluster": "Démarre un cluster Kubernetes local.", "Starts a node.": "", "Starts an existing stopped node in a cluster.": "", "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "Arrêt de \"{{.profile_name}}\" sur {{.driver_name}}...", + "Stopping tunnel for service {{.service}}.": "", "Stops a local kubernetes cluster running in Virtualbox. This command stops the VM\nitself, leaving all files intact. The cluster can be started again with the \"start\" command.": "", "Stops a node in a cluster.": "", "Stops a running local kubernetes cluster": "", + "Successfully added {{.name}} to {{.cluster}}!": "", "Successfully deleted all profiles": "", "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "", "Successfully powered off Hyper-V. minikube driver -- {{.driver}}": "", @@ -384,16 +394,16 @@ "Suggestion: {{.advice}}": "", "Suggestion: {{.fix}}": "", "Target directory {{.path}} must be an absolute path": "", + "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}": "Le pilote \"{{.driver_name}}\" nécessite de disposer de droits racine. Veuillez exécuter minikube à l'aide de \"sudo minikube --vm-driver={{.driver_name}}\".", - "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver should not be used with root privileges.": "", "The \"{{.name}}\" cluster has been deleted.": "Le cluster \"{{.name}}\" a été supprimé.", - "The 'none' driver does not respect the --cpus flag": "", - "The 'none' driver does not respect the --memory flag": "", - "The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "L'isolation fournie par le pilote \"none\" (aucun) est limitée, ce qui peut diminuer la sécurité et la fiabilité du système.", "The '{{.addonName}}' addon is enabled": "", "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "", + "The '{{.name}} driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", + "The '{{.name}}' driver does not respect the --cpus flag": "", + "The '{{.name}}' driver does not respect the --memory flag": "", "The CIDR to be used for service cluster IPs.": "Méthode CIDR à exploiter pour les adresses IP des clusters du service.", "The CIDR to be used for the minikube VM (virtualbox driver only)": "Méthode CIDR à exploiter pour la VM minikube (pilote virtualbox uniquement).", "The KVM QEMU connection URI. (kvm2 driver only)": "URI de connexion QEMU de la KVM (pilote kvm2 uniquement).", @@ -426,11 +436,13 @@ "The name of the network plugin.": "", "The name of the node to add.": "", "The name of the node to delete": "", + "The name of the node to start": "", "The number of bytes to use for 9p packet payload": "", "The output format. One of 'json', 'table'": "", "The path on the file system where the docs in markdown need to be saved": "", "The podman service within '{{.profile}}' is not active": "", "The service namespace": "", + "The service {{.service}} requires privileged ports to be exposed: {{.ports}}": "", "The services namespace": "", "The time interval for each check that wait performs in seconds": "", "The value passed to --format is invalid": "", @@ -449,14 +461,14 @@ "To connect to this cluster, use: kubectl --context={{.name}}__1": "Pour vous connecter à ce cluster, utilisez la commande \"kubectl --context={{.name}}\".", "To connect to this cluster, use: kubectl --context={{.profile_name}}": "", "To disable this notice, run: 'minikube config set WantUpdateNotification false'\\n": "", - "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --vm-driver={{.old_driver}}'": "", + "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --driver={{.old_driver}}'": "", "To see addons list for other profiles use: `minikube addons -p name list`": "", "To start minikube with HyperV Powershell must be in your PATH`": "", "To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:": "Pour utiliser les commandes kubectl ou minikube sous votre propre nom d'utilisateur, vous devrez peut-être les déplacer. Par exemple, pour écraser vos propres paramètres, exécutez la commande suivante :", "Troubleshooting Commands:": "", "Trying to delete invalid profile {{.profile}}": "", "Unable to bind flags": "", - "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/": "", + "Unable to determine a default driver to use. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/": "", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", "Unable to generate docs": "", @@ -494,6 +506,9 @@ "Usage: minikube delete": "", "Usage: minikube delete --all --purge": "", "Usage: minikube node [add|start|stop|delete]": "", + "Usage: minikube node delete [name]": "", + "Usage: minikube node start [name]": "", + "Usage: minikube node stop [name]": "", "Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "", "Use 'kubect get po -A' to find the correct and namespace name": "", "Use -A to specify all namespaces": "", @@ -545,7 +560,7 @@ "bash completion failed": "", "call with cleanup=true to remove old tunnels": "", "command runner": "", - "config modifies minikube config files using subcommands like \"minikube config set vm-driver kvm\"\nConfigurable fields:\\n\\n": "", + "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields:\\n\\n": "", "config view failed": "", "creating api client": "", "dashboard service is not running: {{.error}}": "", @@ -555,10 +570,13 @@ "enable failed": "", "error creating clientset": "", "error creating machine client": "", + "error getting ssh port": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", + "error stopping tunnel": "", "failed to open browser: {{.error}}": "", "if true, will embed the certs in kubeconfig.": "", + "if you want to create a profile you can by this command: minikube start -p {{.profile_name}}": "", "kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "", "kubectl and minikube configuration will be stored in {{.home_folder}}": "Les configurations kubectl et minikube seront stockées dans le dossier {{.home_folder}}.", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", @@ -577,12 +595,12 @@ "mkcmp is used to compare performance of two minikube binaries": "", "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "", - "name is required": "", "namespaces to pause": "", "namespaces to unpause": "", "not enough arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", "pause containers": "", "profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`": "", + "profile {{.name}} is not running.": "", "reload cached images.": "", "reloads images previously added using the 'cache add' subcommand": "", "retrieving node": "", @@ -609,7 +627,6 @@ "usage: minikube addons open ADDON_NAME": "", "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", - "usage: minikube delete --all": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", "zsh completion failed": "", "{{.driver}} does not appear to be installed": "", @@ -620,7 +637,6 @@ "{{.name}} cluster does not exist": "", "{{.name}} has no available configuration options": "", "{{.name}} is already running": "", - "{{.name}} is already stopped": "", "{{.name}} was successfully configured": "", "{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster": "", "{{.prefix}}minikube {{.version}} on {{.platform}}": "{{.prefix}}minikube {{.version}} sur {{.platform}}", diff --git a/translations/ja.json b/translations/ja.json index 7ad4dd5929..364ee9562b 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -5,6 +5,7 @@ "\"{{.name}}\" profile does not exist": "「{{.name}}」というプロファイルは存在しません", "\"{{.name}}\" profile does not exist, trying anyways.": "", "\"{{.profile_name}}\" VM does not exist, nothing to stop": "「{{.profile_name}}」というVMは存在しません。停止すべき対象がありません", + "\"{{.profile_name}}\" does not exist, nothing to stop": "", "\"{{.profile_name}}\" host does not exist, unable to show an IP": "「{{.profile_name}}」というホストは存在しません。IPを表示できません", "\"{{.profile_name}}\" stopped.": "「{{.profile_name}}」が停止しました。", "'none' driver does not support 'minikube docker-env' command": "「none」ドライバーは「minikube docker-env」コマンドをサポートしていません", @@ -28,7 +29,7 @@ "Add an image to local cache.": "イメージをローカルキャッシュに追加します", "Add machine IP to NO_PROXY environment variable": "", "Add or delete an image from the local cache.": "", - "Adding node {{.name}} to cluster {{.profile}}": "", + "Adding node {{.name}} to cluster {{.cluster}}": "", "Additional help topics": "", "Additional mount options, such as cache=fscache": "", "Adds a node to the given cluster config, and starts it.": "", @@ -46,6 +47,8 @@ "Automatically selected the {{.driver}} driver. Other choices: {{.alternates}}": "", "Available Commands": "", "Basic Commands:": "", + "Because you are using docker driver on Mac, the terminal needs to be open to run it.": "", + "Bind Address: {{.Address}}": "", "Block until the apiserver is servicing API requests": "", "Cannot find directory {{.path}} for mount": "", "Cannot use both --output and --format options": "", @@ -62,15 +65,13 @@ "Configuring local host environment ...": "", "Confirm that you have a working internet connection and that your VM has not run out of resources by using: 'minikube logs'": "", "Confirm that you have supplied the correct value to --hyperv-virtual-switch using the 'Get-VMSwitch' command": "", - "Could not get profile flag": "", "Could not process error from failed deletion": "", "Could not process errors from failed deletion": "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn.": "使用するイメージミラーの国コード。グローバルのものを使用する場合は空のままにします。中国本土のユーザーの場合は、「cn」に設定します。", - "Created a new profile : {{.profile_name}}": "", - "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", - "Creating a new profile failed": "", + "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", "Creating mount {{.name}} ...": "マウント {{.name}} を作成しています...", "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "", + "DEPRECATED, use `driver` instead.": "", "Default group id used for the mount": "", "Default user id used for the mount": "", "Delete an image from the local cache.": "", @@ -79,6 +80,7 @@ "Deletes a local kubernetes cluster. This command deletes the VM, and removes all associated files.": "ローカルの Kubernetes クラスタを削除します。このコマンドによって、VM とそれに関連付けられているすべてのファイルが削除されます。", "Deletes a node from a cluster.": "", "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "{{.driver_name}} の「{{.profile_name}}」を削除しています...", + "Deleting node {{.name}} from cluster {{.cluster}}": "", "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)": "VM が起動する前にハードウェアの仮想化の可用性チェックを無効にします(virtualbox ドライバのみ)", "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list": "", @@ -99,6 +101,7 @@ "Download complete!": "ダウンロードが完了しました。", "Downloading VM boot image ...": "", "Downloading driver {{.driver}}:": "", + "Downloading preloaded images tarball for k8s {{.version}} ...": "", "Downloading {{.name}} {{.version}}": "", "ERROR creating `registry-creds-acr` secret": "", "ERROR creating `registry-creds-dpr` secret": "", @@ -140,7 +143,7 @@ "Error getting host IP": "", "Error getting host status": "", "Error getting machine logs": "", - "Error getting profiles to delete": "", + "Error getting port binding for '{{.driver_name}} driver: {{.error}}": "", "Error getting service status": "", "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "", "Error getting ssh client": "", @@ -172,6 +175,7 @@ "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images to tar": "", + "Failed to cache kubectl": "", "Failed to change permissions for {{.minikube_dir_path}}: {{.error}}": "{{.minikube_dir_path}} に対する権限を変更できませんでした。{{.error}}", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", @@ -179,7 +183,7 @@ "Failed to delete cluster: {{.error}}__1": "クラスタを削除できませんでした。{{.error}}", "Failed to delete images": "", "Failed to delete images from config": "", - "Failed to download kubectl": "", + "Failed to delete node {{.name}}": "", "Failed to enable container runtime": "", "Failed to generate config": "", "Failed to get bootstrapper": "", @@ -196,6 +200,8 @@ "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.": "", "Failed to setup certs": "", "Failed to setup kubeconfig": "", + "Failed to start node {{.name}}": "", + "Failed to stop node {{.name}}": "", "Failed to update cluster": "", "Failed to update config": "", "Failed unmount: {{.error}}": "", @@ -230,12 +236,13 @@ "If set, pause all namespaces": "", "If set, unpause all namespaces": "", "If the above advice does not help, please let us know:": "", + "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.": "", "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --vm-driver=none.": "true の場合、現在のブートストラッパの Docker イメージをキャッシュに保存して、マシンに読み込みます。--vm-driver=none の場合は常に false です。", "If true, only download and cache files for later use - don't install or start anything.": "true の場合、後で使用できるようにファイルのダウンロードとキャッシュ保存だけが行われます。インストールも起動も行われません。", "If true, the added node will be marked for work. Defaults to true.": "", "If true, the node added will also be a control plane in addition to a worker.": "", "If using the none driver, ensure that systemctl is installed": "", - "If you are running minikube within a VM, consider using --vm-driver=none:": "", + "If you are running minikube within a VM, consider using --driver=none:": "", "Images Commands:": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "Docker デーモンに渡す Docker レジストリが安全ではありません。デフォルトのサービス CIDR 範囲が自動的に追加されます。", @@ -277,6 +284,7 @@ "No minikube profile was found. You can create one using `minikube start`.": "", "Node may be unable to resolve external DNS records": "", "Node operations": "", + "Node {{.name}} was successfully deleted.": "", "None of the known repositories in your location are accessible. Using {{.image_repository_name}} as fallback.": "使用しているロケーション内で既知のいずれのリポジトリにもアクセスできません。フォールバックとして {{.image_repository_name}} を使用します。", "None of the known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "既知のいずれのリポジトリにもアクセスできません。--image-repository フラグとともに代替のイメージ リポジトリを指定することを検討してください。", "Not passing {{.name}}={{.value}} to docker env.": "", @@ -371,13 +379,16 @@ "Specify the mount filesystem type (supported types: 9p)": "", "Starting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", "Starting node": "", + "Starting tunnel for service {{.service}}.": "", "Starts a local kubernetes cluster": "ローカルの Kubernetes クラスタを起動します", "Starts a node.": "", "Starts an existing stopped node in a cluster.": "", "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Stopping tunnel for service {{.service}}.": "", "Stops a local kubernetes cluster running in Virtualbox. This command stops the VM\nitself, leaving all files intact. The cluster can be started again with the \"start\" command.": "", "Stops a node in a cluster.": "", "Stops a running local kubernetes cluster": "", + "Successfully added {{.name}} to {{.cluster}}!": "", "Successfully deleted all profiles": "", "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "", "Successfully powered off Hyper-V. minikube driver -- {{.driver}}": "", @@ -385,17 +396,17 @@ "Suggestion: {{.advice}}": "", "Suggestion: {{.fix}}": "", "Target directory {{.path}} must be an absolute path": "", + "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}": "「{{.driver_name}}」ドライバにはルート権限が必要です。「sudo minikube --vm-driver={{.driver_name}}」を使用して minikube を実行してください", - "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver should not be used with root privileges.": "", "The \"{{.name}}\" cluster has been deleted.": "「{{.name}}」クラスタが削除されました。", "The \"{{.name}}\" cluster has been deleted.__1": "「{{.name}}」クラスタが削除されました。", - "The 'none' driver does not respect the --cpus flag": "", - "The 'none' driver does not respect the --memory flag": "", - "The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "ドライバに「none」を指定すると、分離が制限され、システムのセキュリティと信頼性が低下する可能性があります。", "The '{{.addonName}}' addon is enabled": "", "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "", + "The '{{.name}} driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", + "The '{{.name}}' driver does not respect the --cpus flag": "", + "The '{{.name}}' driver does not respect the --memory flag": "", "The CIDR to be used for service cluster IPs.": "サービス クラスタ IP に使用される CIDR。", "The CIDR to be used for the minikube VM (virtualbox driver only)": "minikube VM に使用される CIDR(virtualbox ドライバのみ)", "The KVM QEMU connection URI. (kvm2 driver only)": "KVM QEMU 接続 URI(kvm2 ドライバのみ)", @@ -428,11 +439,13 @@ "The name of the network plugin.": "", "The name of the node to add.": "", "The name of the node to delete": "", + "The name of the node to start": "", "The number of bytes to use for 9p packet payload": "", "The output format. One of 'json', 'table'": "", "The path on the file system where the docs in markdown need to be saved": "", "The podman service within '{{.profile}}' is not active": "", "The service namespace": "", + "The service {{.service}} requires privileged ports to be exposed: {{.ports}}": "", "The services namespace": "", "The time interval for each check that wait performs in seconds": "", "The value passed to --format is invalid": "", @@ -451,14 +464,14 @@ "To connect to this cluster, use: kubectl --context={{.name}}__1": "このクラスタに接続するには、「kubectl --context={{.name}}」を使用します", "To connect to this cluster, use: kubectl --context={{.profile_name}}": "", "To disable this notice, run: 'minikube config set WantUpdateNotification false'\\n": "", - "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --vm-driver={{.old_driver}}'": "", + "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --driver={{.old_driver}}'": "", "To see addons list for other profiles use: `minikube addons -p name list`": "", "To start minikube with HyperV Powershell must be in your PATH`": "", "To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:": "kubectl か minikube コマンドを独自のユーザーとして使用するには、そのコマンドの再配置が必要な場合があります。たとえば、独自の設定を上書きするには、以下を実行します。", "Troubleshooting Commands:": "", "Trying to delete invalid profile {{.profile}}": "", "Unable to bind flags": "", - "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/": "", + "Unable to determine a default driver to use. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/": "", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", "Unable to generate docs": "", @@ -496,6 +509,9 @@ "Usage: minikube delete": "", "Usage: minikube delete --all --purge": "", "Usage: minikube node [add|start|stop|delete]": "", + "Usage: minikube node delete [name]": "", + "Usage: minikube node start [name]": "", + "Usage: minikube node stop [name]": "", "Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "", "Use 'kubect get po -A' to find the correct and namespace name": "", "Use -A to specify all namespaces": "", @@ -544,7 +560,7 @@ "bash completion failed": "", "call with cleanup=true to remove old tunnels": "", "command runner": "", - "config modifies minikube config files using subcommands like \"minikube config set vm-driver kvm\"\nConfigurable fields:\\n\\n": "", + "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields:\\n\\n": "", "config view failed": "", "creating api client": "", "dashboard service is not running: {{.error}}": "", @@ -554,10 +570,13 @@ "enable failed": "", "error creating clientset": "", "error creating machine client": "", + "error getting ssh port": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", + "error stopping tunnel": "", "failed to open browser: {{.error}}": "", "if true, will embed the certs in kubeconfig.": "", + "if you want to create a profile you can by this command: minikube start -p {{.profile_name}}": "", "kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "", "kubectl and minikube configuration will be stored in {{.home_folder}}": "kubectl と minikube の構成は {{.home_folder}} に保存されます", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", @@ -576,12 +595,12 @@ "mkcmp is used to compare performance of two minikube binaries": "", "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "", - "name is required": "", "namespaces to pause": "", "namespaces to unpause": "", "not enough arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", "pause containers": "", "profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`": "", + "profile {{.name}} is not running.": "", "reload cached images.": "", "reloads images previously added using the 'cache add' subcommand": "", "retrieving node": "", @@ -608,7 +627,6 @@ "usage: minikube addons open ADDON_NAME": "", "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", - "usage: minikube delete --all": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", "zsh completion failed": "", "{{.driver}} does not appear to be installed": "", @@ -619,7 +637,6 @@ "{{.name}} cluster does not exist": "", "{{.name}} has no available configuration options": "", "{{.name}} is already running": "", - "{{.name}} is already stopped": "", "{{.name}} was successfully configured": "", "{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster": "", "{{.prefix}}minikube {{.version}} on {{.platform}}": "{{.platform}} 上の {{.prefix}}minikube {{.version}}", diff --git a/translations/pl.json b/translations/pl.json index 7c3cfbd8f6..8b1d51fd03 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -4,6 +4,7 @@ "\"{{.name}}\" profile does not exist": "Profil \"{{.name}}\" nie istnieje", "\"{{.name}}\" profile does not exist, trying anyways.": "", "\"{{.profile_name}}\" VM does not exist, nothing to stop": "Maszyna wirtualna \"{{.profile_name}}\" nie istnieje. Nie można zatrzymać", + "\"{{.profile_name}}\" does not exist, nothing to stop": "", "\"{{.profile_name}}\" host does not exist, unable to show an IP": "Profil \"{{.profile_name}}\" nie istnieje. Nie można wyświetlić adresu IP ", "\"{{.profile_name}}\" stopped.": "Zatrzymano \"{{.profile_name}}\"", "'none' driver does not support 'minikube docker-env' command": "sterownik 'none' nie wspiera komendy 'minikube docker-env'", @@ -24,7 +25,7 @@ "Add an image to local cache.": "", "Add machine IP to NO_PROXY environment variable": "", "Add or delete an image from the local cache.": "", - "Adding node {{.name}} to cluster {{.profile}}": "", + "Adding node {{.name}} to cluster {{.cluster}}": "", "Additional help topics": "Dodatkowe tematy pomocy", "Additional mount options, such as cache=fscache": "Dodatkowe opcje montowania, jak na przykład cache=fscache", "Adds a node to the given cluster config, and starts it.": "", @@ -42,6 +43,8 @@ "Automatically selected the {{.driver}} driver. Other choices: {{.alternates}}": "", "Available Commands": "Dostępne polecenia", "Basic Commands:": "Podstawowe polecenia", + "Because you are using docker driver on Mac, the terminal needs to be open to run it.": "", + "Bind Address: {{.Address}}": "", "Block until the apiserver is servicing API requests": "", "Cannot find directory {{.path}} for mount": "Nie można odnoleść folderu {{.path}} do zamontowania", "Cannot use both --output and --format options": "", @@ -59,15 +62,15 @@ "Configuring local host environment ...": "Konfiguruje lokalne środowisko hosta", "Confirm that you have a working internet connection and that your VM has not run out of resources by using: 'minikube logs'": "", "Confirm that you have supplied the correct value to --hyperv-virtual-switch using the 'Get-VMSwitch' command": "", - "Could not get profile flag": "", "Could not process error from failed deletion": "", "Could not process errors from failed deletion": "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn.": "", "Created a new profile : {{.profile_name}}": "Stworzono nowy profil : {{.profile_name}}", - "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", + "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", "Creating a new profile failed": "Tworzenie nowego profilu nie powiodło się", "Creating mount {{.name}} ...": "", "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "Tworzenie {{.driver_name}} (CPUs={{.number_of_cpus}}, Pamięć={{.memory_size}}MB, Dysk={{.disk_size}}MB)...", + "DEPRECATED, use `driver` instead.": "", "Default group id used for the mount": "Domyślne id groupy użyte dla montowania", "Default user id used for the mount": "Domyślne id użytkownia użyte dla montowania ", "Delete an image from the local cache.": "", @@ -76,6 +79,7 @@ "Deletes a local kubernetes cluster. This command deletes the VM, and removes all associated files.": "Usuwa lokalny klaster kubernetesa. Ta komenda usuwa maszynę wirtualna i wszystkie powiązane pliki.", "Deletes a node from a cluster.": "", "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "Usuwanie \"{{.profile_name}}\" - {{.driver_name}}...", + "Deleting node {{.name}} from cluster {{.cluster}}": "", "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)": "", "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list": "", @@ -94,6 +98,7 @@ "Download complete!": "Pobieranie zakończone!", "Downloading VM boot image ...": "Pobieranie obrazu maszyny wirtualnej ...", "Downloading driver {{.driver}}:": "", + "Downloading preloaded images tarball for k8s {{.version}} ...": "", "Downloading {{.name}} {{.version}}": "Pobieranie {{.name}} {{.version}}", "ERROR creating `registry-creds-acr` secret": "", "ERROR creating `registry-creds-dpr` secret": "", @@ -134,7 +139,7 @@ "Error getting host IP": "", "Error getting host status": "", "Error getting machine logs": "", - "Error getting profiles to delete": "", + "Error getting port binding for '{{.driver_name}} driver: {{.error}}": "", "Error getting service status": "", "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "", "Error getting ssh client": "", @@ -167,12 +172,14 @@ "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images to tar": "", + "Failed to cache kubectl": "", "Failed to change permissions for {{.minikube_dir_path}}: {{.error}}": "Nie udało się zmienić uprawnień pliku {{.minikube_dir_path}}: {{.error}}", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", "Failed to delete cluster: {{.error}}": "", "Failed to delete images": "", "Failed to delete images from config": "", + "Failed to delete node {{.name}}": "", "Failed to download kubectl": "Pobieranie kubectl nie powiodło się", "Failed to enable container runtime": "", "Failed to generate config": "", @@ -190,6 +197,8 @@ "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.": "", "Failed to setup certs": "Konfiguracja certyfikatów nie powiodła się", "Failed to setup kubeconfig": "Konfiguracja kubeconfig nie powiodła się", + "Failed to start node {{.name}}": "", + "Failed to stop node {{.name}}": "", "Failed to update cluster": "Aktualizacja klastra nie powiodła się", "Failed to update config": "Aktualizacja konfiguracji nie powiodła się", "Failed unmount: {{.error}}": "", @@ -223,12 +232,12 @@ "If set, pause all namespaces": "", "If set, unpause all namespaces": "", "If the above advice does not help, please let us know:": "", - "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --vm-driver=none.": "", + "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.": "", "If true, only download and cache files for later use - don't install or start anything.": "", "If true, the added node will be marked for work. Defaults to true.": "", "If true, the node added will also be a control plane in addition to a worker.": "", "If using the none driver, ensure that systemctl is installed": "Jeśli użyto sterownika 'none', upewnij się że systemctl jest zainstalowany", - "If you are running minikube within a VM, consider using --vm-driver=none:": "", + "If you are running minikube within a VM, consider using --driver=none:": "", "Images Commands:": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "", "Install VirtualBox, or select an alternative value for --vm-driver": "", @@ -269,6 +278,7 @@ "No minikube profile was found. You can create one using `minikube start`.": "", "Node may be unable to resolve external DNS records": "", "Node operations": "", + "Node {{.name}} was successfully deleted.": "", "None of the known repositories in your location are accessible. Using {{.image_repository_name}} as fallback.": "", "None of the known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "", "Not passing {{.name}}={{.value}} to docker env.": "", @@ -363,13 +373,16 @@ "Specify the mount filesystem type (supported types: 9p)": "", "Starting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", "Starting node": "", + "Starting tunnel for service {{.service}}.": "", "Starts a local kubernetes cluster": "Uruchamianie lokalnego klastra kubernetesa", "Starts a node.": "", "Starts an existing stopped node in a cluster.": "", "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "Zatrzymywanie \"{{.profile_name}}\" - {{.driver_name}}...", + "Stopping tunnel for service {{.service}}.": "", "Stops a local kubernetes cluster running in Virtualbox. This command stops the VM\nitself, leaving all files intact. The cluster can be started again with the \"start\" command.": "", "Stops a node in a cluster.": "", "Stops a running local kubernetes cluster": "Zatrzymuje lokalny klaster kubernetesa", + "Successfully added {{.name}} to {{.cluster}}!": "", "Successfully deleted all profiles": "", "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "Pomyślnie zamontowano {{.sourcePath}} do {{.destinationPath}}", "Successfully powered off Hyper-V. minikube driver -- {{.driver}}": "", @@ -378,15 +391,16 @@ "Suggestion: {{.fix}}": "", "Target directory {{.path}} must be an absolute path": "", "The \"{{.cluster_name}}\" cluster has been deleted.": "Klaster \"{{.cluster_name}}\" został usunięty", + "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.": "Sterownik \"{{.driver_name}}\" wymaga uprawnień root'a. Użyj 'sudo minikube --vm-driver={{.driver_name}}'", "The \"{{.driver_name}}\" driver should not be used with root privileges.": "", "The \"{{.name}}\" cluster has been deleted.": "Klaster \"{{.name}}\" został usunięty", - "The 'none' driver does not respect the --cpus flag": "", - "The 'none' driver does not respect the --memory flag": "", - "The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "", "The '{{.addonName}}' addon is enabled": "", "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "", + "The '{{.name}} driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", + "The '{{.name}}' driver does not respect the --cpus flag": "", + "The '{{.name}}' driver does not respect the --memory flag": "", "The CIDR to be used for service cluster IPs.": "", "The CIDR to be used for the minikube VM (virtualbox driver only)": "", "The KVM QEMU connection URI. (kvm2 driver only)": "", @@ -417,11 +431,13 @@ "The name of the network plugin.": "Nazwa pluginu sieciowego", "The name of the node to add.": "", "The name of the node to delete": "", + "The name of the node to start": "", "The number of bytes to use for 9p packet payload": "", "The output format. One of 'json', 'table'": "", "The path on the file system where the docs in markdown need to be saved": "", "The podman service within '{{.profile}}' is not active": "", "The service namespace": "", + "The service {{.service}} requires privileged ports to be exposed: {{.ports}}": "", "The services namespace": "", "The time interval for each check that wait performs in seconds": "", "The value passed to --format is invalid": "Wartość przekazana do --format jest nieprawidłowa", @@ -438,14 +454,14 @@ "To connect to this cluster, use: kubectl --context={{.profile_name}}": "Aby połaczyć się z klastem uzyj: kubectl --context={{.profile_name}}", "To disable this notice, run: 'minikube config set WantUpdateNotification false'": "Aby wyłączyć te notyfikację, użyj: 'minikube config set WantUpdateNotification false'", "To disable this notice, run: 'minikube config set WantUpdateNotification false'\\n": "", - "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --vm-driver={{.old_driver}}'": "", + "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --driver={{.old_driver}}'": "", "To see addons list for other profiles use: `minikube addons -p name list`": "", "To start minikube with HyperV Powershell must be in your PATH`": "Aby uruchomić minikube z HyperV Powershell musi znajdować się w zmiennej PATH", "To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:": "", "Troubleshooting Commands:": "", "Trying to delete invalid profile {{.profile}}": "", "Unable to bind flags": "", - "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/": "", + "Unable to determine a default driver to use. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/": "", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", "Unable to generate docs": "", @@ -481,6 +497,9 @@ "Usage: minikube delete": "", "Usage: minikube delete --all --purge": "", "Usage: minikube node [add|start|stop|delete]": "", + "Usage: minikube node delete [name]": "", + "Usage: minikube node start [name]": "", + "Usage: minikube node stop [name]": "", "Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "", "Use 'kubect get po -A' to find the correct and namespace name": "", "Use -A to specify all namespaces": "", @@ -531,7 +550,7 @@ "bash completion failed": "", "call with cleanup=true to remove old tunnels": "", "command runner": "", - "config modifies minikube config files using subcommands like \"minikube config set vm-driver kvm\"\nConfigurable fields:\\n\\n": "", + "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields:\\n\\n": "", "config view failed": "", "creating api client": "", "dashboard service is not running: {{.error}}": "", @@ -541,10 +560,13 @@ "enable failed": "", "error creating clientset": "", "error creating machine client": "", + "error getting ssh port": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", + "error stopping tunnel": "", "failed to open browser: {{.error}}": "Nie udało się otworzyć przeglądarki: {{.error}}", "if true, will embed the certs in kubeconfig.": "", + "if you want to create a profile you can by this command: minikube start -p {{.profile_name}}": "", "kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "", "kubectl and minikube configuration will be stored in {{.home_folder}}": "konfiguracja minikube i kubectl będzie przechowywana w katalogu {{.home_dir}}", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "kubectl nie zostało odnaleźione w zmiennej środowiskowej ${PATH}. Instrukcja instalacji: https://kubernetes.io/docs/tasks/tools/install-kubectl/", @@ -563,12 +585,12 @@ "mkcmp is used to compare performance of two minikube binaries": "", "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "Montowanie się nie powiodło", - "name is required": "", "namespaces to pause": "", "namespaces to unpause": "", "not enough arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", "pause containers": "", "profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`": "", + "profile {{.name}} is not running.": "", "reload cached images.": "", "reloads images previously added using the 'cache add' subcommand": "", "retrieving node": "", @@ -596,7 +618,6 @@ "usage: minikube addons open ADDON_NAME": "", "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", - "usage: minikube delete --all": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", "zsh completion failed": "", "{{.addonName}} was successfully enabled": "{{.addonName}} został aktywowany pomyślnie", @@ -608,7 +629,6 @@ "{{.name}} cluster does not exist": "Klaster {{.name}} nie istnieje", "{{.name}} has no available configuration options": "{{.name}} nie posiada opcji configuracji", "{{.name}} is already running": "", - "{{.name}} is already stopped": "", "{{.name}} was successfully configured": "{{.name}} skonfigurowano pomyślnie", "{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster": "", "{{.prefix}}minikube {{.version}} on {{.platform}}": "{{.prefix}}minikube {{.version}} na {{.platform}}", diff --git a/translations/zh-CN.json b/translations/zh-CN.json index 4b6ce53343..fde8a85f6a 100644 --- a/translations/zh-CN.json +++ b/translations/zh-CN.json @@ -5,6 +5,7 @@ "\"{{.name}}\" profile does not exist": "“{{.name}}”配置文件不存在", "\"{{.name}}\" profile does not exist, trying anyways.": "", "\"{{.profile_name}}\" VM does not exist, nothing to stop": "\"{{.profile_name}}\" 虚拟机不存在,没有什么可供停止的", + "\"{{.profile_name}}\" does not exist, nothing to stop": "", "\"{{.profile_name}}\" host does not exist, unable to show an IP": "\"{{.profile_name}}\" 主机不存在,无法显示其IP", "\"{{.profile_name}}\" stopped.": "\"{{.profile_name}}\" 已停止", "'none' driver does not support 'minikube docker-env' command": "'none' 驱动不支持 'minikube docker-env' 命令", @@ -29,7 +30,7 @@ "Add an image to local cache.": "将 image 添加到本地缓存。", "Add machine IP to NO_PROXY environment variable": "将机器IP添加到环境变量 NO_PROXY 中", "Add or delete an image from the local cache.": "在本地缓存中添加或删除 image。", - "Adding node {{.name}} to cluster {{.profile}}": "", + "Adding node {{.name}} to cluster {{.cluster}}": "", "Additional help topics": "其他帮助", "Additional mount options, such as cache=fscache": "其他挂载选项,例如:cache=fscache", "Adds a node to the given cluster config, and starts it.": "", @@ -49,6 +50,8 @@ "Automatically selected the {{.driver}} driver. Other choices: {{.alternates}}": "", "Available Commands": "可用命令", "Basic Commands:": "基本命令:", + "Because you are using docker driver on Mac, the terminal needs to be open to run it.": "", + "Bind Address: {{.Address}}": "", "Block until the apiserver is servicing API requests": "阻塞直到 apiserver 为 API 请求提供服务", "Cannot find directory {{.path}} for mount": "找不到用来挂载的 {{.path}} 目录", "Cannot use both --output and --format options": "不能同时使用 --output 和 --format 选项", @@ -72,10 +75,12 @@ "Could not process errors from failed deletion": "无法处理删除失败的错误", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn.": "需要使用的镜像镜像的国家/地区代码。留空以使用全球代码。对于中国大陆用户,请将其设置为 cn。", "Created a new profile : {{.profile_name}}": "创建了新的配置文件:{{.profile_name}}", + "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "", "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...": "正在 {{.driver_name}} 容器中 创建 Kubernetes,(CPUs={{.number_of_cpus}}), 内存={{.memory_size}}MB ({{.host_memory_size}}MB 可用", "Creating a new profile failed": "创建新的配置文件失败", "Creating mount {{.name}} ...": "正在创建装载 {{.name}}…", "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "正在创建 {{.driver_name}} 虚拟机(CPUs={{.number_of_cpus}},Memory={{.memory_size}}MB, Disk={{.disk_size}}MB)...", + "DEPRECATED, use `driver` instead.": "", "Default group id used for the mount": "用于挂载默认的 group id", "Default user id used for the mount": "用于挂载默认的 user id", "Delete an image from the local cache.": "从本地缓存中删除 image。", @@ -84,6 +89,7 @@ "Deletes a local kubernetes cluster. This command deletes the VM, and removes all associated files.": "删除本地 kubernetes 集群。此命令会删除虚拟机并移除所有关联的文件。", "Deletes a node from a cluster.": "", "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "正在删除 {{.driver_name}} 中的“{{.profile_name}}”…", + "Deleting node {{.name}} from cluster {{.cluster}}": "", "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox driver only)": "禁用在启动虚拟机之前检查硬件虚拟化的可用性(仅限 virtualbox 驱动程序)", "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "禁用虚拟机管理器中的动态内存,或者使用 --memory 传入更大的值", "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list": "在 minikube 中禁用插件 w/ADDON_NAME(例如:minikube addons disable dashboard)。查看相关可用的插件列表,请使用:minikube addons list", @@ -103,6 +109,7 @@ "Download complete!": "下载完成!", "Downloading VM boot image ...": "正在下载 VM boot image...", "Downloading driver {{.driver}}:": "正在下载驱动 {{.driver}}:", + "Downloading preloaded images tarball for k8s {{.version}} ...": "", "Downloading {{.name}} {{.version}}": "正在下载 {{.name}} {{.version}}", "ERROR creating `registry-creds-acr` secret": "", "ERROR creating `registry-creds-dpr` secret": "创建 `registry-creds-dpr` secret 时出错", @@ -153,6 +160,7 @@ "Error getting host status": "获取 host status 时出错", "Error getting machine logs": "获取 machine logs 时出错", "Error getting machine status": "获取 machine status 时出错", + "Error getting port binding for '{{.driver_name}} driver: {{.error}}": "", "Error getting profiles to delete": "获取待删除配置文件时出错", "Error getting service status": "获取 service status 时出错", "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "使用 namespace: {{.namespace}} 和 labels {{.labelName}}:{{.addonName}} 获取 service 时出错:{{.error}}", @@ -190,6 +198,7 @@ "Failed to cache binaries": "缓存二进制文件失败", "Failed to cache images": "缓存镜像时失败", "Failed to cache images to tar": "缓存镜像到 tar 压缩包时出错", + "Failed to cache kubectl": "", "Failed to change permissions for {{.minikube_dir_path}}: {{.error}}": "未能更改 {{.minikube_dir_path}} 的权限:{{.error}}", "Failed to check if machine exists": "无法检测机器是否存在", "Failed to check main repository and mirrors for images for images": "无法检测主仓库和镜像仓库中的镜像", @@ -197,6 +206,7 @@ "Failed to delete cluster: {{.error}}__1": "未能删除集群:{{.error}}", "Failed to delete images": "删除镜像时失败", "Failed to delete images from config": "无法删除配置的镜像", + "Failed to delete node {{.name}}": "", "Failed to download kubectl": "下载 kubectl 失败", "Failed to enable container runtime": "", "Failed to generate config": "无法生成配置", @@ -215,6 +225,8 @@ "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.": "未能设置 NO_PROXY 环境变量。请使用“export NO_PROXY=$NO_PROXY,{{.ip}}”。", "Failed to setup certs": "设置 certs 失败", "Failed to setup kubeconfig": "设置 kubeconfig 失败", + "Failed to start node {{.name}}": "", + "Failed to stop node {{.name}}": "", "Failed to update cluster": "更新 cluster 失败", "Failed to update config": "更新 config 失败", "Failed unmount: {{.error}}": "unmount 失败:{{.error}}", @@ -249,12 +261,13 @@ "If set, pause all namespaces": "", "If set, unpause all namespaces": "", "If the above advice does not help, please let us know:": "", + "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.": "", "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --vm-driver=none.": "如果为 true,请缓存当前引导程序的 docker 镜像并将其加载到机器中。在 --vm-driver=none 情况下始终为 false。", "If true, only download and cache files for later use - don't install or start anything.": "如果为 true,仅会下载和缓存文件以备后用 - 不会安装或启动任何项。", "If true, the added node will be marked for work. Defaults to true.": "", "If true, the node added will also be a control plane in addition to a worker.": "", "If using the none driver, ensure that systemctl is installed": "", - "If you are running minikube within a VM, consider using --vm-driver=none:": "", + "If you are running minikube within a VM, consider using --driver=none:": "", "Images Commands:": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "", "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.": "传递给 Docker 守护进程的不安全 Docker 注册表。系统会自动添加默认服务 CIDR 范围。", @@ -281,22 +294,23 @@ "Log into or run a command on a machine with SSH; similar to 'docker-machine ssh'": "", "Log into or run a command on a machine with SSH; similar to 'docker-machine ssh'.": "", "Message Size: {{.size}}": "", - "Minikube is a CLI tool that provisions and manages single-node Kubernetes clusters optimized for development workflows.": "", + "Minikube is a CLI tool that provisions and manages single-node Kubernetes clusters optimized for development workflows.": "Minikube 是一个命令行工具,它提供和管理针对开发工作流程优化的单节点 Kubernetes 集群。", "Minikube is a tool for managing local Kubernetes clusters.": "", - "Modify minikube config": "", - "Modify minikube's kubernetes addons": "", + "Modify minikube config": "修改 minikube 配置", + "Modify minikube's kubernetes addons": "修改 minikube 的 kubernetes 插件", "Mount type: {{.name}}": "", "Mounting host path {{.sourcePath}} into VM as {{.destinationPath}} ...": "", - "Mounts the specified directory into minikube": "", - "Mounts the specified directory into minikube.": "", + "Mounts the specified directory into minikube": "将指定的目录挂载到 minikube", + "Mounts the specified directory into minikube.": "将指定的目录挂载到 minikube。", "Multiple errors deleting profiles": "删除配置文件时出现多个错误", "Multiple minikube profiles were found -": "发现了多个 minikube 配置文件 -", "NIC Type used for host only network. One of Am79C970A, Am79C973, 82540EM, 82543GC, 82545EM, or virtio (virtualbox driver only)": "网卡类型仅用于主机网络。Am79C970A, Am79C973, 82540EM, 82543GC, 82545EM 之一,或 virtio(仅限 VirtualBox 驱动程序)", "NOTE: This process must stay alive for the mount to be accessible ...": "", - "Networking and Connectivity Commands:": "", + "Networking and Connectivity Commands:": "网络和连接命令:", "No minikube profile was found. You can create one using `minikube start`.": "", "Node may be unable to resolve external DNS records": "", "Node operations": "", + "Node {{.name}} was successfully deleted.": "", "None of the known repositories in your location are accessible. Using {{.image_repository_name}} as fallback.": "您所在位置的已知存储库都无法访问。正在将 {{.image_repository_name}} 用作后备存储库。", "None of the known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "已知存储库都无法访问。请考虑使用 --image-repository 标志指定备选镜像存储库", "Not passing {{.name}}={{.value}} to docker env.": "", @@ -314,11 +328,11 @@ "Options: {{.options}}": "", "Outputs minikube shell completion for the given shell (bash or zsh)": "", "Outputs minikube shell completion for the given shell (bash or zsh)\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\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\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": "", - "Pause": "", - "Paused kubelet and {{.count}} containers": "", - "Paused kubelet and {{.count}} containers in: {{.namespaces}}": "", - "Permissions: {{.octalMode}} ({{.writtenMode}})": "", - "Please enter a value:": "", + "Pause": "暂停", + "Paused kubelet and {{.count}} containers": "已暂停 kubelet 和 {{.count}} 个容器", + "Paused kubelet and {{.count}} containers in: {{.namespaces}}": "已暂停 {{.namespaces}} 中的 kubelet 和 {{.count}} 个容器", + "Permissions: {{.octalMode}} ({{.writtenMode}})": "权限: {{.octalMode}} ({{.writtenMode}})", + "Please enter a value:": "请输入一个值:", "Please install the minikube hyperkit VM driver, or select an alternative --vm-driver": "", "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver": "", "Please make sure the service you are looking for is deployed or is in the correct namespace.": "", @@ -327,23 +341,23 @@ "Populates the specified folder with documentation in markdown about minikube": "", "Powering off \"{{.profile_name}}\" via SSH ...": "正在通过 SSH 关闭“{{.profile_name}}”…", "Preparing Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}} ...": "正在 {{.runtime}} {{.runtimeVersion}} 中准备 Kubernetes {{.k8sVersion}}…", - "Print current and latest version number": "", - "Print the version of minikube": "", - "Print the version of minikube.": "", - "Problems detected in {{.entry}}:": "", - "Problems detected in {{.name}}:": "", - "Profile gets or sets the current minikube profile": "", + "Print current and latest version number": "打印当前和最新版本版本", + "Print the version of minikube": "打印 minikube 版本", + "Print the version of minikube.": "打印 minikube 版本。", + "Problems detected in {{.entry}}:": "在 {{.entry}} 中 检测到问题:", + "Problems detected in {{.name}}:": "在 {{.name}} 中 检测到问题:", + "Profile gets or sets the current minikube profile": "获取或设置当前的 minikube 配置文件", "Profile name \"{{.profilename}}\" is minikube keyword. To delete profile use command minikube delete -p \u003cprofile name\u003e": "配置文件名称 \"{{.profilename}}\" 是 minikube 的一个关键字。使用 minikube delete -p \u003cprofile name\u003e 命令 删除配置文件", "Provide VM UUID to restore MAC address (hyperkit driver only)": "提供虚拟机 UUID 以恢复 MAC 地址(仅限 hyperkit 驱动程序)", "Pulling images ...": "拉取镜像 ...", "Reboot to complete VirtualBox installation, verify that VirtualBox is not blocked by your system, and/or use another hypervisor": "重启以完成 VirtualBox 安装,检查 VirtualBox 未被您的操作系统禁用,或者使用其他的管理程序。", "Rebuild libvirt with virt-network support": "", - "Received {{.name}} signal": "", - "Reconfiguring existing host ...": "", + "Received {{.name}} signal": "收到 {{.name}} 信号", + "Reconfiguring existing host ...": "重新配置现有主机", "Registry mirrors to pass to the Docker daemon": "传递给 Docker 守护进程的注册表镜像", "Reinstall VirtualBox and reboot. Alternatively, try the kvm2 driver: https://minikube.sigs.k8s.io/docs/reference/drivers/kvm2/": "", "Reinstall VirtualBox and verify that it is not blocked: System Preferences -\u003e Security \u0026 Privacy -\u003e General -\u003e Some system software was blocked from loading": "", - "Related issues:": "", + "Related issues:": "相关问题:", "Relaunching Kubernetes using {{.bootstrapper}} ...": "正在使用 {{.bootstrapper}} 重新启动 Kubernetes…", "Removed all traces of the \"{{.name}}\" cluster.": "", "Removing {{.directory}} ...": "正在移除 {{.directory}}…", @@ -351,15 +365,15 @@ "Requested disk size {{.requested_size}} is less than minimum of {{.minimum_size}}": "请求的磁盘大小 {{.requested_size}} 小于最小值 {{.minimum_size}}", "Requested memory allocation ({{.memory}}MB) is less than the default memory allocation of {{.default_memorysize}}MB. Beware that minikube might not work correctly or crash unexpectedly.": "请求的内存分配 ({{.memory}}MB) 小于默认内存分配 {{.default_memorysize}}MB。请注意 minikube 可能无法正常运行或可能会意外崩溃。", "Requested memory allocation {{.requested_size}} is less than the minimum allowed of {{.minimum_size}}": "请求的内存分配 {{.requested_size}} 小于允许的 {{.minimum_size}} 最小值", - "Retrieve the ssh identity key path of the specified cluster": "", - "Retrieve the ssh identity key path of the specified cluster.": "", - "Retrieves the IP address of the running cluster": "", + "Retrieve the ssh identity key path of the specified cluster": "检索指定集群的 ssh 密钥路径", + "Retrieve the ssh identity key path of the specified cluster.": "检索指定集群的 ssh 密钥路径。", + "Retrieves the IP address of the running cluster": "检索正在运行的群集的 IP 地址", "Retrieves the IP address of the running cluster, and writes it to STDOUT.": "", "Retrieves the IP address of the running cluster, checks it\n\t\t\twith IP in kubeconfig, and corrects kubeconfig if incorrect.": "", "Returns the value of PROPERTY_NAME from the minikube config file. Can be overwritten at runtime by flags or environmental variables.": "", "Run 'kubectl describe pod coredns -n kube-system' and check for a firewall or DNS conflict": "", "Run 'minikube delete' to delete the stale VM, or and ensure that minikube is running as the same user you are issuing this command with": "执行 'minikube delete' 以删除过时的虚拟机,或者确保 minikube 以与您发出此命令的用户相同的用户身份运行", - "Run kubectl": "", + "Run kubectl": "运行 kubectl", "Run minikube from the C: drive.": "", "Run the kubernetes client, download it if necessary. Remember -- after kubectl!\n\nExamples:\nminikube kubectl -- --help\nminikube kubectl -- get pods --namespace kube-system": "", "Run the minikube command as an Administrator": "", @@ -372,11 +386,11 @@ "Set this flag to delete the '.minikube' folder from your user directory.": "设置这个标志来删除您用户目录下的 '.minikube' 文件夹。", "Sets an individual value in a minikube config file": "", "Sets the PROPERTY_NAME config value to PROPERTY_VALUE\n\tThese values can be overwritten by flags or environment variables at runtime.": "", - "Sets up docker env variables; similar to '$(docker-machine env)'": "", - "Sets up docker env variables; similar to '$(docker-machine env)'.": "", - "Sets up podman env variables; similar to '$(podman-machine env)'": "", - "Sets up podman env variables; similar to '$(podman-machine env)'.": "", - "Setting profile failed": "", + "Sets up docker env variables; similar to '$(docker-machine env)'": "设置 docker env 变量;类似于 '$(docker-machine env)'", + "Sets up docker env variables; similar to '$(docker-machine env)'.": "设置 docker env 变量;类似于 '$(docker-machine env)'。", + "Sets up podman env variables; similar to '$(podman-machine env)'": "设置 podman env 变量;类似于 '$(podman-machine env)'", + "Sets up podman env variables; similar to '$(podman-machine env)'.": "设置 podman env 变量;类似于 '$(podman-machine env)'。", + "Setting profile failed": "设置配置文件失败", "Show a list of global command-line options (applies to all commands).": "显示全局命令行选项列表 (应用于所有命令)。", "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.": "", @@ -394,13 +408,16 @@ "Specify the mount filesystem type (supported types: 9p)": "", "Starting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", "Starting node": "", + "Starting tunnel for service {{.service}}.": "", "Starts a local kubernetes cluster": "启动本地 kubernetes 集群", "Starts a node.": "", "Starts an existing stopped node in a cluster.": "", "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Stopping tunnel for service {{.service}}.": "", "Stops a local kubernetes cluster running in Virtualbox. This command stops the VM\nitself, leaving all files intact. The cluster can be started again with the \"start\" command.": "", "Stops a node in a cluster.": "", - "Stops a running local kubernetes cluster": "", + "Stops a running local kubernetes cluster": "停止正在运行的本地 kubernetes 集群", + "Successfully added {{.name}} to {{.cluster}}!": "", "Successfully deleted all profiles": "成功删除所有配置文件", "Successfully deleted profile \\\"{{.name}}\\\"": "成功删除配置文件 \\\"{{.name}}\\\"", "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "", @@ -409,17 +426,19 @@ "Suggestion: {{.advice}}": "建议:{{.advice}}", "Suggestion: {{.fix}}": "建议:{{.fix}}", "Target directory {{.path}} must be an absolute path": "", + "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}": "“{{.driver_name}}”驱动程序需要根权限。请使用“sudo minikube --vm-driver={{.driver_name}}”运行 minikube", - "The \"{{.driver_name}}\" driver requires root privileges. Please run minikube using 'sudo minikube --vm-driver={{.driver_name}}'.": "", "The \"{{.driver_name}}\" driver should not be used with root privileges.": "", "The \"{{.name}}\" cluster has been deleted.": "“{{.name}}”集群已删除。", "The \"{{.name}}\" cluster has been deleted.__1": "“{{.name}}”集群已删除。", "The 'none' driver does not respect the --cpus flag": "'none' 驱动程序不遵循 --cpus 标志", "The 'none' driver does not respect the --memory flag": "'none' 驱动程序不遵循 --memory 标志", - "The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "“none”驱动程序提供有限的隔离功能,并且可能会降低系统安全性和可靠性。", - "The '{{.addonName}}' addon is enabled": "", - "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "", + "The '{{.addonName}}' addon is enabled": "启动 '{{.addonName}}' 插件", + "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "'{{.driver}}' 驱动程序需要提升权限,将执行以下命令:\\n\\n{{ .example }}\\n", + "The '{{.name}} driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "", + "The '{{.name}}' driver does not respect the --cpus flag": "", + "The '{{.name}}' driver does not respect the --memory flag": "", "The CIDR to be used for service cluster IPs.": "需要用于服务集群 IP 的 CIDR。", "The CIDR to be used for the minikube VM (virtualbox driver only)": "需要用于 minikube 虚拟机的 CIDR(仅限 virtualbox 驱动程序)", "The KVM QEMU connection URI. (kvm2 driver only)": "KVM QEMU 连接 URI。(仅限 kvm2 驱动程序)", @@ -452,11 +471,13 @@ "The name of the network plugin.": "", "The name of the node to add.": "", "The name of the node to delete": "", + "The name of the node to start": "", "The number of bytes to use for 9p packet payload": "", "The output format. One of 'json', 'table'": "输出的格式。'json' 或者 'table'", "The path on the file system where the docs in markdown need to be saved": "", "The podman service within '{{.profile}}' is not active": "", "The service namespace": "", + "The service {{.service}} requires privileged ports to be exposed: {{.ports}}": "", "The services namespace": "", "The time interval for each check that wait performs in seconds": "", "The value passed to --format is invalid": "", @@ -475,13 +496,14 @@ "To connect to this cluster, use: kubectl --context={{.name}}__1": "如需连接到此集群,请使用 kubectl --context={{.name}}", "To connect to this cluster, use: kubectl --context={{.profile_name}}": "", "To disable this notice, run: 'minikube config set WantUpdateNotification false'\\n": "", - "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --vm-driver={{.old_driver}}'": "", + "To proceed, either:\n\n 1) Delete the existing \"{{.profile_name}}\" cluster using: '{{.command}} delete'\n\n * or *\n\n 2) Start the existing \"{{.profile_name}}\" cluster using: '{{.command}} start --driver={{.old_driver}}'": "", "To see addons list for other profiles use: `minikube addons -p name list`": "", "To start minikube with HyperV Powershell must be in your PATH`": "", "To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:": "如需以您自己的用户身份使用 kubectl 或 minikube 命令,您可能需要重新定位该命令。例如,如需覆盖您的自定义设置,请运行:", - "Troubleshooting Commands:": "", + "Troubleshooting Commands:": "故障排除命令ƒ", "Trying to delete invalid profile {{.profile}}": "尝试删除无效的配置文件 {{.profile}}", "Unable to bind flags": "无法绑定标志", + "Unable to determine a default driver to use. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/": "", "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/": "无法确定要使用的默认驱动。尝试通过 --vm-dirver 指定,或者查阅 https://minikube.sigs.k8s.io/docs/start/", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", @@ -515,33 +537,36 @@ "Update server returned an empty list": "", "Upgrade to QEMU v3.1.0+, run 'virt-host-validate', or ensure that you are not running in a nested VM environment.": "", "Upgrading from Kubernetes {{.old}} to {{.new}}": "正在从 Kubernetes {{.old}} 升级到 {{.new}}", - "Usage": "", - "Usage: minikube completion SHELL": "", - "Usage: minikube delete": "", + "Usage": "使用方法", + "Usage: minikube completion SHELL": "使用方法:minikube completion SHELL", + "Usage: minikube delete": "使用方法:minikube delete", "Usage: minikube delete --all --purge": "使用方法:minikube delete --all --purge", - "Usage: minikube node [add|start|stop|delete]": "", - "Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "", + "Usage: minikube node [add|start|stop|delete]": "使用方法:minikube node [add|start|stop|delete]", + "Usage: minikube node delete [name]": "", + "Usage: minikube node start [name]": "", + "Usage: minikube node stop [name]": "", + "Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "使用 \"{{.CommandPath}} [command] --help\" 可以获取有关命令的更多信息", "Use 'kubect get po -A' to find the correct and namespace name": "使用 'kubect get po -A' 来查询正确的命名空间名称", - "Use -A to specify all namespaces": "", - "Use VirtualBox to remove the conflicting VM and/or network interfaces": "", + "Use -A to specify all namespaces": "使用 -A 指定所有 namespaces", + "Use VirtualBox to remove the conflicting VM and/or network interfaces": "使用 VirtualBox 删除有冲突的 虚拟机 和/或 网络接口", "Use native Golang SSH client (default true). Set to 'false' to use the command line 'ssh' command when accessing the docker machine. Useful for the machine drivers when they will not start with 'Waiting for SSH'.": "", - "User ID: {{.userID}}": "", + "User ID: {{.userID}}": "用户 ID: {{.userID}}", "Userspace file server is shutdown": "", "Userspace file server:": "", "Using image repository {{.name}}": "正在使用镜像存储库 {{.name}}", "Using the '{{.runtime}}' runtime with the 'none' driver is an untested configuration!": "同时使用 'none' 驱动以及 '{{.runtime}}' 运行时是未经测试过的配置!", - "Using the running {{.driver_name}} \"{{.profile_name}}\" VM ...": "", - "Using the {{.driver}} driver based on existing profile": "", - "Using the {{.driver}} driver based on user configuration": "", + "Using the running {{.driver_name}} \"{{.profile_name}}\" VM ...": "使用正在运行的 {{.driver_name}} \"{{.profile_name}}\" 虚拟机", + "Using the {{.driver}} driver based on existing profile": "根据现有的配置文件使用 {{.driver}} 驱动程序", + "Using the {{.driver}} driver based on user configuration": "根据用户配置使用 {{.driver}} 驱动程序", "VM driver is one of: %v": "虚拟机驱动程序是以下项之一:%v", "VM is unable to access {{.repository}}, you may need to configure a proxy or set --image-repository": "虚拟机无权访问 {{.repository}},或许您需要配置代理或者设置 --image-repository", "VM may be unable to resolve external DNS records": "虚拟机可能无法解析外部 DNS 记录", - "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.": "", - "Verify the IP address of the running cluster in kubeconfig.": "", - "Verifying dashboard health ...": "", - "Verifying proxy health ...": "", + "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.": "验证是否正确设置了 HTTP_PROXY 和 HTTPS_PROXY 环境变量。", + "Verify the IP address of the running cluster in kubeconfig.": "在 kubeconfig 中验证正在运行的集群 IP 地址。", + "Verifying dashboard health ...": "正在验证 dashboard 运行情况 ...", + "Verifying proxy health ...": "正在验证 proxy 运行状况 ...", "Verifying:": "正在验证:", - "Version: {{.version}}": "", + "Version: {{.version}}": "版本: {{.version}}", "VirtualBox and Hyper-V are having a conflict. Use '--vm-driver=hyperv' or disable Hyper-V using: 'bcdedit /set hypervisorlaunchtype off'": "", "VirtualBox cannot create a network, probably because it conflicts with an existing network that minikube no longer knows about. Try running 'minikube delete'": "", "VirtualBox is broken. Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.": "", @@ -573,20 +598,23 @@ "bash completion failed": "", "call with cleanup=true to remove old tunnels": "", "command runner": "", - "config modifies minikube config files using subcommands like \"minikube config set vm-driver kvm\"\nConfigurable fields:\\n\\n": "", + "config modifies minikube config files using subcommands like \"minikube config set driver kvm\"\nConfigurable fields:\\n\\n": "", "config view failed": "", "creating api client": "", "dashboard service is not running: {{.error}}": "", - "disable failed": "", + "disable failed": "禁用失败", "dry-run mode. Validates configuration, but does not mutate system state": "", "dry-run validation complete!": "", - "enable failed": "", + "enable failed": "开启失败", "error creating clientset": "", "error creating machine client": "", + "error getting ssh port": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", + "error stopping tunnel": "", "failed to open browser: {{.error}}": "", "if true, will embed the certs in kubeconfig.": "", + "if you want to create a profile you can by this command: minikube start -p {{.profile_name}}": "", "kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "kubeadm 检测一个到与其他进程的 TCP 端口冲突:或许是另外的本地安装的 Kubernetes 导致。执行 lsof -p\u003cport\u003e 查找并杀死这些进程", "kubectl and minikube configuration will be stored in {{.home_folder}}": "kubectl 和 minikube 配置将存储在 {{.home_folder}} 中", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", @@ -594,7 +622,7 @@ "loading config": "", "logdir set failed": "", "machine '{{.name}}' does not exist. Proceeding ahead with recreating VM.": "", - "max time to wait per Kubernetes core services to be healthy.": "", + "max time to wait per Kubernetes core services to be healthy.": "每个 Kubernetes 核心服务保持健康所需的最长时间。", "minikube addons list --output OUTPUT. json, list": "", "minikube is exiting due to an error. If the above message is not useful, open an issue:": "由于出错 minikube 正在退出。如果以上信息没有帮助,请提交问题反馈:", "minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.": "", @@ -606,12 +634,12 @@ "mkcmp is used to compare performance of two minikube binaries": "mkcmp 用于对比两个 minikube 二进制的性能", "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "", - "name is required": "", "namespaces to pause": "", "namespaces to unpause": "", "not enough arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", - "pause containers": "", + "pause containers": "暂停容器", "profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`": "", + "profile {{.name}} is not running.": "", "reload cached images.": "重新加载缓存的镜像", "reloads images previously added using the 'cache add' subcommand": "重新加载之前通过子命令 'cache add' 添加的镜像", "retrieving node": "", @@ -621,16 +649,16 @@ "status text failure": "", "toom any arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "", "tunnel creates a route to services deployed with type LoadBalancer and sets their Ingress to their ClusterIP. for a detailed example see https://minikube.sigs.k8s.io/docs/tasks/loadbalancer": "", - "tunnel makes services of type LoadBalancer accessible on localhost": "", + "tunnel makes services of type LoadBalancer accessible on localhost": "隧道使本地主机上可以访问 LoadBalancer 类型的服务", "unable to bind flags": "", "unable to delete minikube config folder": "无法删除 minikube 配置目录", "unable to set logtostderr": "", - "unpause Kubernetes": "", + "unpause Kubernetes": "恢复 Kubernetes", "unset failed": "", "unsets PROPERTY_NAME from the minikube config file. Can be overwritten by flags or environmental variables": "", "unsets an individual value in a minikube config file": "", "unsupported or missing driver: {{.name}}": "不支持或者缺失驱动:{{.name}}", - "update config": "", + "update config": "更新配置", "usage: minikube addons configure ADDON_NAME": "", "usage: minikube addons disable ADDON_NAME": "", "usage: minikube addons enable ADDON_NAME": "", @@ -638,7 +666,6 @@ "usage: minikube addons open ADDON_NAME": "", "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", - "usage: minikube delete --all": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", "zsh completion failed": "", "{{.driver}} does not appear to be installed": "似乎并未安装 {{.driver}}", @@ -649,7 +676,6 @@ "{{.name}} cluster does not exist": "", "{{.name}} has no available configuration options": "", "{{.name}} is already running": "", - "{{.name}} is already stopped": "", "{{.name}} was successfully configured": "", "{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster": "{{.path}} 的版本是 {{.client_version}},且与 Kubernetes {{.cluster_version}} 不兼容。您需要更新 {{.path}} 或者使用 'minikube kubectl' 连接到这个集群", "{{.prefix}}minikube {{.version}} on {{.platform}}": "{{.platform}} 上的 {{.prefix}}minikube {{.version}}",