diff --git a/.gitignore b/.gitignore index 1f55d284e7..811be834c3 100644 --- a/.gitignore +++ b/.gitignore @@ -29,12 +29,12 @@ _testmain.go /out /_gopath - #iso version file deploy/iso/minikube-iso/board/coreos/minikube/rootfs-overlay/etc/VERSION /pkg/minikube/assets/assets.go /pkg/minikube/translate/translations.go +/pkg/minikube/translate/translations.go-e /minikube .DS_Store @@ -42,3 +42,5 @@ deploy/iso/minikube-iso/board/coreos/minikube/rootfs-overlay/etc/VERSION /.idea /.vscode + +test/integration/testdata/minikube-linux-amd64-latest-stable diff --git a/.gitmodules b/.gitmodules index 15220d4613..29c209d1ea 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "site/themes/hugo-whisper-theme"] - path = site/themes/hugo-whisper-theme - url = https://github.com/jugglerx/hugo-whisper-theme.git +[submodule "site/themes/docsy"] + path = site/themes/docsy + url = https://github.com/google/docsy.git diff --git a/.travis.yml b/.travis.yml index 649c6a6190..0f82068494 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,12 @@ language: go os: linux -sudo: required -go: - - 1.x +matrix: + include: + - go: 1.12.7 + - language: python + before_install: pip install flake8 + script: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics before_install: - sudo apt-get install -y libvirt-dev diff --git a/CHANGELOG.md b/CHANGELOG.md index 524833af4e..61bd70ea7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,65 @@ -# Minikube Release Notes +# Release Notes + +## Version 1.3.0 - 2019-08-XX (TBD) + +* Added a new command: profile list [#4811](https://github.com/kubernetes/minikube/pull/4811) +* Update latest kubernetes version to v1.15.1 [#4915](https://github.com/kubernetes/minikube/pull/4915) +* logs: Add container status & cruntime logs [#4960](https://github.com/kubernetes/minikube/pull/4960) +* Automatically set flags for MINIKUBE_ prefixed env vars [#4607](https://github.com/kubernetes/minikube/pull/4607) +* hyperv: Run "sudo poweroff" before stopping VM [#4758](https://github.com/kubernetes/minikube/pull/4758) +* Decrease ReasonableStartTime from 10 minutes to 5 minutes [#4961](https://github.com/kubernetes/minikube/pull/4961) +* Remove ingress-nginx default backend [#4786](https://github.com/kubernetes/minikube/pull/4786) +* Upgrade nginx ingress to 0.25.0 [#4785](https://github.com/kubernetes/minikube/pull/4785) +* Bump k8s.io/kubernetes to 1.15.0 [#4719](https://github.com/kubernetes/minikube/pull/4719) +* Upgrade Docker, from 18.09.7 to 18.09.8 [#4818](https://github.com/kubernetes/minikube/pull/4818) +* Upgrade Docker, from 18.09.6 to 18.09.7 [#4657](https://github.com/kubernetes/minikube/pull/4657) +* Upgrade crio to 1.15.0 [#4703](https://github.com/kubernetes/minikube/pull/4703) +* Update crictl to v1.15.0 [#4761](https://github.com/kubernetes/minikube/pull/4761) +* Upgrade Podman to 1.4 [#4610](https://github.com/kubernetes/minikube/pull/4610) +* Upgrade libmachine to master [#4817](https://github.com/kubernetes/minikube/pull/4817) +* Add linux packaging for the kvm2 driver binary [#4556](https://github.com/kubernetes/minikube/pull/4556) +* Unset profile when it is deleted [#4922](https://github.com/kubernetes/minikube/pull/4922) +* more reliable stop for none driver [#4871](https://github.com/kubernetes/minikube/pull/4871) +* Fix regression caused by registry-proxy [#4805](https://github.com/kubernetes/minikube/pull/4805) +* Warn if hyperkit version is old [#4691](https://github.com/kubernetes/minikube/pull/4691) +* Add warn if kvm driver version is old [#4676](https://github.com/kubernetes/minikube/pull/4676) +* Add T versions of the console convenience functions [#4796](https://github.com/kubernetes/minikube/pull/4796) +* Remove deprecated drivers: kvm-old and xhyve [#4781](https://github.com/kubernetes/minikube/pull/4781) +* Don't disable other container engines when --vm_driver=none [#4545](https://github.com/kubernetes/minikube/pull/4545) +* Proxy: handle lower case proxy env vars [#4602](https://github.com/kubernetes/minikube/pull/4602) +* virtualbox: Make DNS settings configurable [#4619](https://github.com/kubernetes/minikube/pull/4619) +* Add support to custom qemu uri on kvm2 driver [#4401](https://github.com/kubernetes/minikube/pull/4401) +* Update Ingress-NGINX to 0.24.1 Release [#4583](https://github.com/kubernetes/minikube/pull/4583) + +A big thanks goes out to our crew of merry contributors: + +- Aida Ghazizadeh +- Anders F Björklund +- Ben Ebsworth +- Benjamin Howell +- cclauss +- Christophe VILA +- Deepjyoti Mondal +- fang duan +- Francis +- Gustavo Belfort +- Himanshu Pandey +- Jituri, Pranav +- josedonizetti +- Jose Donizetti +- Kazuki Suda +- Kyle Bai +- Marcos Diez +- Medya Ghazizadeh +- Nabarun Pal +- Om Kumar +- Pranav Jituri +- RA489 +- serhat çetinkaya +- Sharif Elgamal +- Stuart P. Bentley +- Thomas Strömberg +- Zoltán Reegn ## Version 1.2.0 - 2019-06-24 diff --git a/Makefile b/Makefile index 696301d380..5b185cb15a 100755 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ # Bump these on release - and please check ISO_VERSION for correctness. VERSION_MAJOR ?= 1 -VERSION_MINOR ?= 2 +VERSION_MINOR ?= 3 VERSION_BUILD ?= 0 # Default to .0 for higher cache hit rates, as build increments typically don't require new ISO versions ISO_VERSION ?= v$(VERSION_MAJOR).$(VERSION_MINOR).0 @@ -31,21 +31,35 @@ COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true) COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}") HYPERKIT_BUILD_IMAGE ?= karalabe/xgo-1.12.x -# NOTE: "latest" as of 2019-05-09. kube-cross images aren't updated as often as Kubernetes -BUILD_IMAGE ?= k8s.gcr.io/kube-cross:v1.12.5-1 +# NOTE: "latest" as of 2019-07-12. kube-cross images aren't updated as often as Kubernetes +BUILD_IMAGE ?= k8s.gcr.io/kube-cross:v1.12.7-1 ISO_BUILD_IMAGE ?= $(REGISTRY)/buildroot-image -KVM_BUILD_IMAGE ?= $(REGISTRY)/kvm-build-image +KVM_BUILD_IMAGE ?= $(REGISTRY)/kvm-build-image:$(GO_VERSION) ISO_BUCKET ?= minikube/iso MINIKUBE_VERSION ?= $(ISO_VERSION) MINIKUBE_BUCKET ?= minikube/releases MINIKUBE_UPLOAD_LOCATION := gs://${MINIKUBE_BUCKET} +MINIKUBE_RELEASES_URL=https://github.com/kubernetes/minikube/releases/download -KERNEL_VERSION ?= 4.16.14 +KERNEL_VERSION ?= 4.15 + +# Currently *only* used for the KVM_BUILD_IMAGE, see also BUILD_IMAGE above +GO_VERSION ?= 1.12.7 -GO_VERSION ?= $(shell go version | cut -d' ' -f3 | sed -e 's/go//') GOLINT_VERSION ?= v1.17.1 +# Limit number of default jobs, to avoid the CI builds running out of memory +GOLINT_JOBS ?= 4 +# see https://github.com/golangci/golangci-lint#memory-usage-of-golangci-lint +GOLINT_GOGC ?= 8 +# options for lint (golangci-lint) +GOLINT_OPTIONS = --deadline 4m \ + --build-tags "${MINIKUBE_INTEGRATION_BUILD_TAGS}" \ + --enable goimports,gocritic,golint,gocyclo,interfacer,misspell,nakedret,stylecheck,unconvert,unparam \ + --exclude 'variable on range scope.*in function literal|ifElseChain' + + export GO111MODULE := on GOOS ?= $(shell go env GOOS) @@ -74,6 +88,7 @@ MINIKUBE_TEST_FILES := ./cmd/... ./pkg/... # npm install -g markdownlint-cli MARKDOWNLINT ?= markdownlint + MINIKUBE_MARKDOWN_FILES := README.md docs CONTRIBUTING.md CHANGELOG.md MINIKUBE_BUILD_TAGS := container_image_ostree_stub containers_image_openpgp @@ -114,7 +129,7 @@ out/minikube$(IS_EXE): out/minikube-$(GOOS)-$(GOARCH)$(IS_EXE) cp $< $@ out/minikube-windows-amd64.exe: out/minikube-windows-amd64 - mv out/minikube-windows-amd64 out/minikube-windows-amd64.exe + cp out/minikube-windows-amd64 out/minikube-windows-amd64.exe out/minikube-%: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go $(shell find $(CMD_SOURCE_DIRS) -type f -name "*.go") ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y) @@ -128,7 +143,7 @@ e2e-%-$(GOARCH): out/minikube-%-$(GOARCH) GOOS=$* GOARCH=$(GOARCH) go test -c k8s.io/minikube/test/integration --tags="$(MINIKUBE_INTEGRATION_BUILD_TAGS)" -o out/$@ e2e-windows-amd64.exe: e2e-windows-amd64 - mv $(BUILD_DIR)/e2e-windows-amd64 $(BUILD_DIR)/e2e-windows-amd64.exe + cp $(BUILD_DIR)/e2e-windows-amd64 $(BUILD_DIR)/e2e-windows-amd64.exe minikube_iso: # old target kept for making tests happy echo $(ISO_VERSION) > deploy/iso/minikube-iso/board/coreos/minikube/rootfs-overlay/etc/VERSION @@ -196,16 +211,28 @@ integration-versioned: out/minikube test: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go ./test.sh +.PHONY: extract +extract: + go run cmd/extract/extract.go + # Regenerates assets.go when template files have been updated pkg/minikube/assets/assets.go: $(shell find deploy/addons -type f) +ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y) + $(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@) +else which go-bindata || GO111MODULE=off GOBIN=$(GOPATH)/bin go get github.com/jteeuwen/go-bindata/... PATH="$(PATH):$(GOPATH)/bin" go-bindata -nomemcopy -o pkg/minikube/assets/assets.go -pkg assets deploy/addons/... -gofmt -s -w $@ +endif pkg/minikube/translate/translations.go: $(shell find translations/ -type f) +ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y) + $(call DOCKER,$(BUILD_IMAGE),/usr/bin/make $@) +else which go-bindata || GO111MODULE=off GOBIN=$(GOPATH)/bin go get github.com/jteeuwen/go-bindata/... PATH="$(PATH):$(GOPATH)/bin" go-bindata -nomemcopy -o pkg/minikube/translate/translations.go -pkg translate translations/... -gofmt -s -w $@ +endif @#golint: Json should be JSON (compat sed) @sed -i -e 's/Json/JSON/' $@ && rm -f ./-e @@ -268,14 +295,16 @@ out/linters/golangci-lint: mkdir -p out/linters curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b out/linters $(GOLINT_VERSION) +# this one is meant for local use .PHONY: lint lint: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go out/linters/golangci-lint - ./out/linters/golangci-lint run \ - --deadline 4m \ - --build-tags "${MINIKUBE_INTEGRATION_BUILD_TAGS}" \ - --enable goimports,gocritic,golint,gocyclo,interfacer,misspell,nakedret,stylecheck,unconvert,unparam \ - --exclude 'variable on range scope.*in function literal|ifElseChain' \ - ./... + ./out/linters/golangci-lint run ${GOLINT_OPTIONS} ./... + +# 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 +lint-ci: pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go out/linters/golangci-lint + GOGC=${GOLINT_GOGC} ./out/linters/golangci-lint run \ + --concurrency ${GOLINT_JOBS} ${GOLINT_OPTIONS} ./... .PHONY: reportcard reportcard: @@ -288,7 +317,7 @@ mdlint: @$(MARKDOWNLINT) $(MINIKUBE_MARKDOWN_FILES) out/docs/minikube.md: $(shell find cmd) $(shell find pkg/minikube/constants) pkg/minikube/assets/assets.go pkg/minikube/translate/translations.go - go run -ldflags="$(MINIKUBE_LDFLAGS)" hack/help_text/gen_help_text.go + go run -ldflags="$(MINIKUBE_LDFLAGS)" -tags gendocs hack/help_text/gen_help_text.go out/minikube_$(DEB_VERSION).deb: out/minikube-linux-amd64 cp -r installers/linux/deb/minikube_deb_template out/minikube_$(DEB_VERSION) @@ -307,6 +336,20 @@ out/minikube-$(RPM_VERSION).rpm: out/minikube-linux-amd64 out/minikube-$(RPM_VERSION)/minikube.spec rm -rf out/minikube-$(RPM_VERSION) +.PHONY: apt +apt: out/Release + +out/Release: out/minikube_$(DEB_VERSION).deb + ( cd out && apt-ftparchive packages . ) | gzip -c > out/Packages.gz + ( cd out && apt-ftparchive release . ) > out/Release + +.PHONY: yum +yum: out/repodata/repomd.xml + +out/repodata/repomd.xml: out/minikube-$(RPM_VERSION).rpm + createrepo --simple-md-filenames --no-database \ + -u "$(MINIKUBE_RELEASES_URL)/$(VERSION)/" out + .SECONDEXPANSION: TAR_TARGETS_linux := out/minikube-linux-amd64 out/docker-machine-driver-kvm2 TAR_TARGETS_darwin := out/minikube-darwin-amd64 @@ -316,7 +359,7 @@ out/minikube-%-amd64.tar.gz: $$(TAR_TARGETS_$$*) $(TAR_TARGETS_ALL) tar -cvf $@ $^ .PHONY: cross-tars -cross-tars: kvm_in_docker out/minikube-windows-amd64.tar.gz out/minikube-linux-amd64.tar.gz out/minikube-darwin-amd64.tar.gz +cross-tars: out/minikube-windows-amd64.tar.gz out/minikube-linux-amd64.tar.gz out/minikube-darwin-amd64.tar.gz out/minikube-installer.exe: out/minikube-windows-amd64.exe rm -rf out/windows_tmp @@ -332,7 +375,7 @@ out/minikube-installer.exe: out/minikube-windows-amd64.exe mv out/windows_tmp/minikube-installer.exe out/minikube-installer.exe rm -rf out/windows_tmp -out/docker-machine-driver-hyperkit: +out/docker-machine-driver-hyperkit: pkg/minikube/translate/translations.go ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y) $(call DOCKER,$(HYPERKIT_BUILD_IMAGE),CC=o64-clang CXX=o64-clang++ /usr/bin/make $@) else @@ -398,31 +441,55 @@ release-minikube: out/minikube checksum gsutil cp out/minikube-$(GOOS)-$(GOARCH) $(MINIKUBE_UPLOAD_LOCATION)/$(MINIKUBE_VERSION)/minikube-$(GOOS)-$(GOARCH) gsutil cp out/minikube-$(GOOS)-$(GOARCH).sha256 $(MINIKUBE_UPLOAD_LOCATION)/$(MINIKUBE_VERSION)/minikube-$(GOOS)-$(GOARCH).sha256 -out/docker-machine-driver-kvm2: +out/docker-machine-driver-kvm2: pkg/minikube/translate/translations.go +ifeq ($(MINIKUBE_BUILD_IN_DOCKER),y) + docker inspect -f '{{.Id}} {{.RepoTags}}' $(KVM_BUILD_IMAGE) || $(MAKE) kvm-image + $(call DOCKER,$(KVM_BUILD_IMAGE),/usr/bin/make $@ COMMIT=$(COMMIT)) + # make extra sure that we are linking with the older version of libvirt (1.3.1) + test "`strings $@ | grep '^LIBVIRT_[0-9]' | sort | tail -n 1`" = "LIBVIRT_1.2.9" +else go build \ -installsuffix "static" \ -ldflags="$(KVM2_LDFLAGS)" \ - -tags libvirt.1.3.1 \ + -tags "libvirt.1.3.1 without_lxc" \ -o $(BUILD_DIR)/docker-machine-driver-kvm2 \ k8s.io/minikube/cmd/drivers/kvm +endif chmod +X $@ -kvm-image: $(KVM_BUILD_IMAGE) # convenient alias to build the docker container -$(KVM_BUILD_IMAGE): installers/linux/kvm/Dockerfile - docker build --build-arg "GO_VERSION=$(GO_VERSION)" -t $@ -f $< $(dir $<) +out/docker-machine-driver-kvm2_$(DEB_VERSION).deb: out/docker-machine-driver-kvm2 + cp -r installers/linux/deb/kvm2_deb_template out/docker-machine-driver-kvm2_$(DEB_VERSION) + chmod 0755 out/docker-machine-driver-kvm2_$(DEB_VERSION)/DEBIAN + sed -E -i 's/--VERSION--/'$(DEB_VERSION)'/g' out/docker-machine-driver-kvm2_$(DEB_VERSION)/DEBIAN/control + mkdir -p out/docker-machine-driver-kvm2_$(DEB_VERSION)/usr/bin + cp out/docker-machine-driver-kvm2 out/docker-machine-driver-kvm2_$(DEB_VERSION)/usr/bin/docker-machine-driver-kvm2 + fakeroot dpkg-deb --build out/docker-machine-driver-kvm2_$(DEB_VERSION) + rm -rf out/docker-machine-driver-kvm2_$(DEB_VERSION) + +out/docker-machine-driver-kvm2-$(RPM_VERSION).rpm: out/docker-machine-driver-kvm2 + cp -r installers/linux/rpm/kvm2_rpm_template out/docker-machine-driver-kvm2-$(RPM_VERSION) + sed -E -i 's/--VERSION--/'$(RPM_VERSION)'/g' out/docker-machine-driver-kvm2-$(RPM_VERSION)/docker-machine-driver-kvm2.spec + sed -E -i 's|--OUT--|'$(PWD)/out'|g' out/docker-machine-driver-kvm2-$(RPM_VERSION)/docker-machine-driver-kvm2.spec + rpmbuild -bb -D "_rpmdir $(PWD)/out" -D "_rpmfilename docker-machine-driver-kvm2-$(RPM_VERSION).rpm" \ + out/docker-machine-driver-kvm2-$(RPM_VERSION)/docker-machine-driver-kvm2.spec + rm -rf out/docker-machine-driver-kvm2-$(RPM_VERSION) + +.PHONY: kvm-image # convenient alias to build the docker container +kvm-image: installers/linux/kvm/Dockerfile + docker build --build-arg "GO_VERSION=$(GO_VERSION)" -t $(KVM_BUILD_IMAGE) -f $< $(dir $<) @echo "" @echo "$(@) successfully built" kvm_in_docker: - docker inspect $(KVM_BUILD_IMAGE) || $(MAKE) $(KVM_BUILD_IMAGE) + docker inspect -f '{{.Id}} {{.RepoTags}}' $(KVM_BUILD_IMAGE) || $(MAKE) kvm-image rm -f out/docker-machine-driver-kvm2 $(call DOCKER,$(KVM_BUILD_IMAGE),/usr/bin/make out/docker-machine-driver-kvm2 COMMIT=$(COMMIT)) -.PHONY: install-kvm -install-kvm: out/docker-machine-driver-kvm2 +.PHONY: install-kvm-driver +install-kvm-driver: out/docker-machine-driver-kvm2 cp out/docker-machine-driver-kvm2 $(GOBIN)/docker-machine-driver-kvm2 .PHONY: release-kvm-driver -release-kvm-driver: kvm_in_docker checksum install-kvm +release-kvm-driver: install-kvm-driver checksum gsutil cp $(GOBIN)/docker-machine-driver-kvm2 gs://minikube/drivers/kvm/$(VERSION)/ gsutil cp $(GOBIN)/docker-machine-driver-kvm2.sha256 gs://minikube/drivers/kvm/$(VERSION)/ diff --git a/cmd/extract/extract.go b/cmd/extract/extract.go index 501864dc26..c49a5c89a5 100644 --- a/cmd/extract/extract.go +++ b/cmd/extract/extract.go @@ -24,6 +24,9 @@ Usage: from the root minikube directory, go run cmd/extract/extract.go package main import ( + "os" + "strings" + "k8s.io/minikube/pkg/minikube/extract" ) @@ -31,7 +34,19 @@ func main() { paths := []string{"cmd", "pkg"} functions := []string{"translate.T"} outDir := "translations" - err := extract.TranslatableStrings(paths, functions, outDir) + cwd, err := os.Getwd() + if err != nil { + panic("Getting current working directory failed") + } + + if strings.Contains(cwd, "cmd") { + panic("run extract.go from the minikube root directory") + } + + if _, err = os.Stat(extract.ErrMapFile); os.IsNotExist(err) { + panic("err_map.go doesn't exist") + } + err = extract.TranslatableStrings(paths, functions, outDir) if err != nil { panic(err) diff --git a/cmd/minikube/cmd/cache.go b/cmd/minikube/cmd/cache.go index 7b403f4b90..8192a9e0d3 100644 --- a/cmd/minikube/cmd/cache.go +++ b/cmd/minikube/cmd/cache.go @@ -93,8 +93,8 @@ func CacheImagesInConfigFile() error { return machine.CacheImages(images, constants.ImageCacheDir) } -// LoadCachedImagesInConfigFile loads the images currently in the config file (minikube start) -func LoadCachedImagesInConfigFile() error { +// loadCachedImagesInConfigFile loads the images currently in the config file (minikube start) +func loadCachedImagesInConfigFile() error { images, err := imagesInConfigFile() if err != nil { return err @@ -108,5 +108,4 @@ func LoadCachedImagesInConfigFile() error { func init() { cacheCmd.AddCommand(addCacheCmd) cacheCmd.AddCommand(deleteCacheCmd) - RootCmd.AddCommand(cacheCmd) } diff --git a/cmd/minikube/cmd/completion.go b/cmd/minikube/cmd/completion.go index eb697b8834..5c0669d3cd 100644 --- a/cmd/minikube/cmd/completion.go +++ b/cmd/minikube/cmd/completion.go @@ -24,6 +24,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" ) const longDescription = ` @@ -69,10 +70,10 @@ var completionCmd = &cobra.Command{ Long: longDescription, Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { - exit.Usage("Usage: minikube completion SHELL") + exit.UsageT("Usage: minikube completion SHELL") } if args[0] != "bash" && args[0] != "zsh" { - exit.Usage("Sorry, completion support is not yet implemented for %q", args[0]) + exit.UsageT("Sorry, completion support is not yet implemented for {{.name}}", out.V{"name": args[0]}) } else if args[0] == "bash" { err := GenerateBashCompletion(os.Stdout, cmd.Parent()) if err != nil { @@ -278,7 +279,3 @@ __minikube_bash_source <(__minikube_convert_bash_to_zsh) return nil } - -func init() { - RootCmd.AddCommand(completionCmd) -} diff --git a/cmd/minikube/cmd/config/addons_list.go b/cmd/minikube/cmd/config/addons_list.go index 483a543c94..bf05d976a7 100644 --- a/cmd/minikube/cmd/config/addons_list.go +++ b/cmd/minikube/cmd/config/addons_list.go @@ -41,7 +41,7 @@ var addonsListCmd = &cobra.Command{ Long: "Lists all available minikube addons as well as their current statuses (enabled/disabled)", Run: func(cmd *cobra.Command, args []string) { if len(args) != 0 { - exit.Usage("usage: minikube addons list") + exit.UsageT("usage: minikube addons list") } err := addonList() if err != nil { diff --git a/cmd/minikube/cmd/config/config.go b/cmd/minikube/cmd/config/config.go index e8143caabc..ac2423760c 100644 --- a/cmd/minikube/cmd/config/config.go +++ b/cmd/minikube/cmd/config/config.go @@ -17,10 +17,6 @@ limitations under the License. package config import ( - "encoding/json" - "fmt" - "io" - "os" "strings" "github.com/golang/glog" @@ -302,7 +298,7 @@ func AddToConfigMap(name string, images []string) error { return err } // Set the values - configFile, err := config.ReadConfig() + cfg, err := config.ReadConfig() if err != nil { return err } @@ -310,16 +306,16 @@ func AddToConfigMap(name string, images []string) error { for _, image := range images { newImages[image] = nil } - if values, ok := configFile[name].(map[string]interface{}); ok { + if values, ok := cfg[name].(map[string]interface{}); ok { for key := range values { newImages[key] = nil } } - if err = s.setMap(configFile, name, newImages); err != nil { + if err = s.setMap(cfg, name, newImages); err != nil { return err } // Write the values - return WriteConfig(configFile) + return config.WriteConfig(constants.ConfigFile, cfg) } // DeleteFromConfigMap deletes entries from a map in the config file @@ -329,45 +325,20 @@ func DeleteFromConfigMap(name string, images []string) error { return err } // Set the values - configFile, err := config.ReadConfig() + cfg, err := config.ReadConfig() if err != nil { return err } - values, ok := configFile[name] + values, ok := cfg[name] if !ok { return nil } for _, image := range images { delete(values.(map[string]interface{}), image) } - if err = s.setMap(configFile, name, values.(map[string]interface{})); err != nil { + if err = s.setMap(cfg, name, values.(map[string]interface{})); err != nil { return err } // Write the values - return WriteConfig(configFile) -} - -// WriteConfig writes a minikube config to the JSON file -func WriteConfig(m config.MinikubeConfig) error { - f, err := os.Create(constants.ConfigFile) - if err != nil { - return fmt.Errorf("create %s: %s", constants.ConfigFile, err) - } - defer f.Close() - err = encode(f, m) - if err != nil { - return fmt.Errorf("encode %s: %s", constants.ConfigFile, err) - } - return nil -} - -func encode(w io.Writer, m config.MinikubeConfig) error { - b, err := json.MarshalIndent(m, "", " ") - if err != nil { - return err - } - - _, err = w.Write(b) - - return err + return config.WriteConfig(constants.ConfigFile, cfg) } diff --git a/cmd/minikube/cmd/config/config_test.go b/cmd/minikube/cmd/config/config_test.go index 5736897d64..56a84b28d0 100644 --- a/cmd/minikube/cmd/config/config_test.go +++ b/cmd/minikube/cmd/config/config_test.go @@ -20,46 +20,8 @@ import ( "bytes" "fmt" "testing" - - "k8s.io/minikube/pkg/minikube/constants" ) -type configTestCase struct { - data string - config map[string]interface{} -} - -var configTestCases = []configTestCase{ - { - data: `{ - "memory": 2 -}`, - config: map[string]interface{}{ - "memory": 2, - }, - }, - { - data: `{ - "ReminderWaitPeriodInHours": 99, - "cpus": 4, - "disk-size": "20g", - "log_dir": "/etc/hosts", - "show-libmachine-logs": true, - "v": 5, - "vm-driver": "kvm" -}`, - config: map[string]interface{}{ - "vm-driver": constants.DriverKvmOld, - "cpus": 4, - "disk-size": "20g", - "v": 5, - "show-libmachine-logs": true, - "log_dir": "/etc/hosts", - "ReminderWaitPeriodInHours": 99, - }, - }, -} - func TestHiddenPrint(t *testing.T) { testCases := []struct { TestString string @@ -90,17 +52,3 @@ func TestHiddenPrint(t *testing.T) { } } } - -func TestWriteConfig(t *testing.T) { - var b bytes.Buffer - for _, tt := range configTestCases { - err := encode(&b, tt.config) - if err != nil { - t.Errorf("Error encoding: %v", err) - } - 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()) - } - b.Reset() - } -} diff --git a/cmd/minikube/cmd/config/configure.go b/cmd/minikube/cmd/config/configure.go index 43ba2a04e1..b51d240063 100644 --- a/cmd/minikube/cmd/config/configure.go +++ b/cmd/minikube/cmd/config/configure.go @@ -20,8 +20,8 @@ import ( "io/ioutil" "github.com/spf13/cobra" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/service" ) @@ -31,7 +31,7 @@ var addonsConfigureCmd = &cobra.Command{ Long: "Configures the addon w/ADDON_NAME within minikube (example: minikube addons configure registry-creds). For a list of available addons use: minikube addons list ", Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { - exit.Usage("usage: minikube addons configure ADDON_NAME") + exit.UsageT("usage: minikube addons configure ADDON_NAME") } addon := args[0] @@ -77,7 +77,7 @@ var addonsConfigureCmd = &cobra.Command{ dat, err := ioutil.ReadFile(gcrPath) if err != nil { - console.Failure("Error reading %s: %v", gcrPath, err) + out.FailureT("Error reading {{.path}}: {{.error}}", out.V{"path": gcrPath, "error": err}) } else { gcrApplicationDefaultCredentials = string(dat) } @@ -109,7 +109,7 @@ var addonsConfigureCmd = &cobra.Command{ }) if err != nil { - console.Failure("ERROR creating `registry-creds-ecr` secret: %v", err) + out.FailureT("ERROR creating `registry-creds-ecr` secret: {{.error}}", out.V{"error": err}) } // Create GCR Secret @@ -127,7 +127,7 @@ var addonsConfigureCmd = &cobra.Command{ }) if err != nil { - console.Failure("ERROR creating `registry-creds-gcr` secret: %v", err) + out.FailureT("ERROR creating `registry-creds-gcr` secret: {{.error}}", out.V{"error": err}) } // Create Docker Secret @@ -146,14 +146,14 @@ var addonsConfigureCmd = &cobra.Command{ }) if err != nil { - console.Warning("ERROR creating `registry-creds-dpr` secret") + out.WarningT("ERROR creating `registry-creds-dpr` secret") } default: - console.Failure("%s has no available configuration options", addon) + out.FailureT("{{.name}} has no available configuration options", out.V{"name": addon}) return } - console.Success("%s was successfully configured", addon) + out.SuccessT("{{.name}} was successfully configured", out.V{"name": addon}) }, } diff --git a/cmd/minikube/cmd/config/disable.go b/cmd/minikube/cmd/config/disable.go index ffabc863f0..6901f43bd4 100644 --- a/cmd/minikube/cmd/config/disable.go +++ b/cmd/minikube/cmd/config/disable.go @@ -18,8 +18,8 @@ package config import ( "github.com/spf13/cobra" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" ) var addonsDisableCmd = &cobra.Command{ @@ -28,7 +28,7 @@ var addonsDisableCmd = &cobra.Command{ Long: "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list ", Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { - exit.Usage("usage: minikube addons disable ADDON_NAME") + exit.UsageT("usage: minikube addons disable ADDON_NAME") } addon := args[0] @@ -36,7 +36,7 @@ var addonsDisableCmd = &cobra.Command{ if err != nil { exit.WithError("disable failed", err) } - console.Success("%s was successfully disabled", addon) + out.SuccessT(`"{{.minikube_addon}}" was successfully disabled`, out.V{"minikube_addon": addon}) }, } diff --git a/cmd/minikube/cmd/config/enable.go b/cmd/minikube/cmd/config/enable.go index 012bb9a5a1..20b018b135 100644 --- a/cmd/minikube/cmd/config/enable.go +++ b/cmd/minikube/cmd/config/enable.go @@ -18,8 +18,8 @@ package config import ( "github.com/spf13/cobra" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" ) var addonsEnableCmd = &cobra.Command{ @@ -28,16 +28,15 @@ var addonsEnableCmd = &cobra.Command{ Long: "Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list ", Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { - exit.Usage("usage: minikube addons enable ADDON_NAME") + exit.UsageT("usage: minikube addons enable ADDON_NAME") } addon := args[0] err := Set(addon, "true") if err != nil { - console.Fatal("enable failed: %v", err) - } else { - console.Success("%s was successfully enabled", addon) + exit.WithError("enable failed", err) } + out.SuccessT("{{.addonName}} was successfully enabled", out.V{"addonName": addon}) }, } diff --git a/cmd/minikube/cmd/config/get.go b/cmd/minikube/cmd/config/get.go index 704a1146f3..fa5747d27f 100644 --- a/cmd/minikube/cmd/config/get.go +++ b/cmd/minikube/cmd/config/get.go @@ -22,7 +22,7 @@ import ( "github.com/spf13/cobra" pkgConfig "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" ) var configGetCmd = &cobra.Command{ @@ -44,7 +44,7 @@ var configGetCmd = &cobra.Command{ return fmt.Errorf("no value for key '%s'", args[0]) } - console.OutLn(val) + out.Ln(val) return nil }, } diff --git a/cmd/minikube/cmd/config/open.go b/cmd/minikube/cmd/config/open.go index 708a590c2d..53d87aa8ad 100644 --- a/cmd/minikube/cmd/config/open.go +++ b/cmd/minikube/cmd/config/open.go @@ -17,16 +17,15 @@ limitations under the License. package config import ( - "os" "text/template" "github.com/spf13/cobra" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/cluster" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/service" ) @@ -48,13 +47,13 @@ var addonsOpenCmd = &cobra.Command{ PreRun: func(cmd *cobra.Command, args []string) { t, err := template.New("addonsURL").Parse(addonsURLFormat) if err != nil { - exit.Usage("The value passed to --format is invalid: %s", err) + exit.UsageT("The value passed to --format is invalid: {{.error}}", out.V{"error": err}) } addonsURLTemplate = t }, Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { - exit.Usage("usage: minikube addons open ADDON_NAME") + exit.UsageT("usage: minikube addons open ADDON_NAME") } addonName := args[0] // TODO(r2d4): config should not reference API, pull this out @@ -67,19 +66,18 @@ var addonsOpenCmd = &cobra.Command{ cluster.EnsureMinikubeRunningOrExit(api, 1) addon, ok := assets.Addons[addonName] // validate addon input if !ok { - exit.WithCode(exit.Data, `addon '%s' is not a valid addon packaged with minikube. + exit.WithCodeT(exit.Data, `addon '{{.name}}' is not a valid addon packaged with minikube. To see the list of available addons run: -minikube addons list`, addonName) +minikube addons list`, out.V{"name": addonName}) } ok, err = addon.IsEnabled() if err != nil { exit.WithError("IsEnabled failed", err) } if !ok { - console.ErrStyle(console.Conflict, `addon '%s' is currently not enabled. + exit.WithCodeT(exit.Unavailable, `addon '{{.name}}' is currently not enabled. To enable this addon run: -minikube addons enable %s`, addonName, addonName) - os.Exit(exit.Unavailable) +minikube addons enable {{.name}}`, out.V{"name": addonName}) } namespace := "kube-system" @@ -87,16 +85,16 @@ minikube addons enable %s`, addonName, addonName) serviceList, err := service.GetServiceListByLabel(namespace, key, addonName) if err != nil { - exit.WithCode(exit.Unavailable, "Error getting service with namespace: %s and labels %s:%s: %v", namespace, key, addonName, err) + exit.WithCodeT(exit.Unavailable, "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}", out.V{"namespace": namespace, "labelName": key, "addonName": addonName, "error": err}) } if len(serviceList.Items) == 0 { - exit.WithCode(exit.Config, `This addon does not have an endpoint defined for the 'addons open' command. -You can add one by annotating a service with the label %s:%s`, key, addonName) + exit.WithCodeT(exit.Config, `This addon does not have an endpoint defined for the 'addons open' command. +You can add one by annotating a service with the label {{.labelName}}:{{.addonName}}`, out.V{"labelName": key, "addonName": addonName}) } for i := range serviceList.Items { svc := serviceList.Items[i].ObjectMeta.Name if err := service.WaitAndMaybeOpenService(api, namespace, svc, addonsURLTemplate, addonsURLMode, https, wait, interval); err != nil { - exit.WithCode(exit.Unavailable, "Wait failed: %v", err) + exit.WithCodeT(exit.Unavailable, "Wait failed: {{.error}}", out.V{"error": err}) } } }, diff --git a/cmd/minikube/cmd/config/profile.go b/cmd/minikube/cmd/config/profile.go index 770e5f6bf2..c15be55847 100644 --- a/cmd/minikube/cmd/config/profile.go +++ b/cmd/minikube/cmd/config/profile.go @@ -22,9 +22,9 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" pkgConfig "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" pkgutil "k8s.io/minikube/pkg/util" ) @@ -36,12 +36,12 @@ var ProfileCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { profile := viper.GetString(pkgConfig.MachineProfile) - console.OutLn("%s", profile) + out.T(out.Empty, profile) os.Exit(0) } if len(args) > 1 { - exit.Usage("usage: minikube profile [MINIKUBE_PROFILE_NAME]") + exit.UsageT("usage: minikube profile [MINIKUBE_PROFILE_NAME]") } profile := args[0] @@ -55,19 +55,19 @@ var ProfileCmd = &cobra.Command{ cc, err := pkgConfig.Load() // might err when loading older version of cfg file that doesn't have KeepContext field if err != nil && !os.IsNotExist(err) { - console.ErrLn("Error loading profile config: %v", err) + out.ErrT(out.Sad, `Error loading profile config: {{.error}}`, out.V{"error": err}) } if err == nil { if cc.MachineConfig.KeepContext { - console.Success("Skipped switching kubectl context for %s , because --keep-context", profile) - console.Success("To connect to this cluster, use: kubectl --context=%s", profile) + out.SuccessT("Skipped switching kubectl context for {{.profile_name}} , because --keep-context", out.V{"profile_name": profile}) + out.SuccessT("To connect to this cluster, use: kubectl --context={{.profile_name}}", out.V{"profile_name": profile}) } else { err := pkgutil.SetCurrentContext(constants.KubeconfigPath, profile) if err != nil { - console.ErrLn("Error while setting kubectl current context : %v", err) + out.ErrT(out.Sad, `Error while setting kubectl current context : {{.error}}`, out.V{"error": err}) } } } - console.Success("minikube profile was successfully set to %s", profile) + out.SuccessT("minikube profile was successfully set to {{.profile_name}}", out.V{"profile_name": profile}) }, } diff --git a/cmd/minikube/cmd/config/profile_list.go b/cmd/minikube/cmd/config/profile_list.go new file mode 100644 index 0000000000..4498e6d33c --- /dev/null +++ b/cmd/minikube/cmd/config/profile_list.go @@ -0,0 +1,76 @@ +/* +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 config + +import ( + "fmt" + "os" + "strconv" + + "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" + + "github.com/olekukonko/tablewriter" + "github.com/spf13/cobra" +) + +var profileListCmd = &cobra.Command{ + Use: "list", + Short: "Lists all minikube profiles.", + Long: "Lists all valid minikube profiles and detects all possible invalid profiles.", + Run: func(cmd *cobra.Command, args []string) { + + var validData [][]string + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Profile", "VM Driver", "NodeIP", "Node Port", "Kubernetes Version"}) + table.SetAutoFormatHeaders(false) + table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: true}) + table.SetCenterSeparator("|") + validProfiles, invalidProfiles, err := config.ListProfiles() + + if len(validProfiles) == 0 || err != nil { + exit.UsageT("No minikube profile was found. you could create one using: `minikube start`") + } + for _, p := range validProfiles { + validData = append(validData, []string{p.Name, p.Config.MachineConfig.VMDriver, p.Config.KubernetesConfig.NodeIP, strconv.Itoa(p.Config.KubernetesConfig.NodePort), p.Config.KubernetesConfig.KubernetesVersion}) + } + + table.AppendBulk(validData) + table.Render() + + if invalidProfiles != nil { + out.T(out.WarningType, "Found {{.number}} invalid profile(s) ! ", out.V{"number": len(invalidProfiles)}) + for _, p := range invalidProfiles { + out.T(out.Empty, "\t "+p.Name) + } + out.T(out.Tip, "You can delete them using the following command(s): ") + for _, p := range invalidProfiles { + out.String(fmt.Sprintf("\t $ minikube delete -p %s \n", p.Name)) + } + + } + if err != nil { + exit.WithCodeT(exit.Config, fmt.Sprintf("error loading profiles: %v", err)) + } + }, +} + +func init() { + ProfileCmd.AddCommand(profileListCmd) +} diff --git a/cmd/minikube/cmd/config/prompt.go b/cmd/minikube/cmd/config/prompt.go index bbfbf19c52..91cbae6b77 100644 --- a/cmd/minikube/cmd/config/prompt.go +++ b/cmd/minikube/cmd/config/prompt.go @@ -25,7 +25,7 @@ import ( "github.com/golang/glog" "golang.org/x/crypto/ssh/terminal" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" ) // AskForYesNoConfirmation asks the user for confirmation. A user must type in "yes" or "no" and @@ -36,7 +36,7 @@ func AskForYesNoConfirmation(s string, posResponses, negResponses []string) bool reader := bufio.NewReader(os.Stdin) for { - console.Out("%s [y/n]: ", s) + out.String("%s [y/n]: ", s) response, err := reader.ReadString('\n') if err != nil { @@ -49,7 +49,7 @@ func AskForYesNoConfirmation(s string, posResponses, negResponses []string) bool case containsString(negResponses, r): return false default: - console.Err("Please type yes or no:") + out.Err("Please type yes or no:") } } } @@ -63,7 +63,7 @@ func AskForStaticValue(s string) string { // Can't have zero length if len(response) == 0 { - console.Err("--Error, please enter a value:") + out.Err("--Error, please enter a value:") continue } return response @@ -78,7 +78,7 @@ func AskForStaticValueOptional(s string) string { } func getStaticValue(reader *bufio.Reader, s string) string { - console.Out("%s", s) + out.String("%s", s) response, err := reader.ReadString('\n') if err != nil { @@ -110,7 +110,7 @@ func concealableAskForStaticValue(readWriter io.ReadWriter, promptString string, } response = strings.TrimSpace(response) if len(response) == 0 { - console.Warning("Please enter a value:") + out.WarningT("Please enter a value:") continue } return response, nil diff --git a/cmd/minikube/cmd/config/set.go b/cmd/minikube/cmd/config/set.go index 3982a8e321..3019c793e2 100644 --- a/cmd/minikube/cmd/config/set.go +++ b/cmd/minikube/cmd/config/set.go @@ -19,6 +19,7 @@ package config import ( "github.com/spf13/cobra" pkgConfig "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" ) @@ -29,7 +30,7 @@ var configSetCmd = &cobra.Command{ These values can be overwritten by flags or environment variables at runtime.`, Run: func(cmd *cobra.Command, args []string) { if len(args) != 2 { - exit.Usage("usage: minikube config set PROPERTY_NAME PROPERTY_VALUE") + exit.UsageT("usage: minikube config set PROPERTY_NAME PROPERTY_VALUE") } err := Set(args[0], args[1]) if err != nil { @@ -71,5 +72,5 @@ func Set(name string, value string) error { } // Write the value - return WriteConfig(config) + return pkgConfig.WriteConfig(constants.ConfigFile, config) } diff --git a/cmd/minikube/cmd/config/unset.go b/cmd/minikube/cmd/config/unset.go index 1ea0723405..fc91390ed8 100644 --- a/cmd/minikube/cmd/config/unset.go +++ b/cmd/minikube/cmd/config/unset.go @@ -19,6 +19,7 @@ package config import ( "github.com/spf13/cobra" pkgConfig "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" ) @@ -28,9 +29,9 @@ var configUnsetCmd = &cobra.Command{ Long: "unsets PROPERTY_NAME from the minikube config file. Can be overwritten by flags or environmental variables", Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { - exit.Usage("usage: minikube config unset PROPERTY_NAME") + exit.UsageT("usage: minikube config unset PROPERTY_NAME") } - err := unset(args[0]) + err := Unset(args[0]) if err != nil { exit.WithError("unset failed", err) } @@ -41,11 +42,12 @@ func init() { ConfigCmd.AddCommand(configUnsetCmd) } -func unset(name string) error { +// Unset unsets a property +func Unset(name string) error { m, err := pkgConfig.ReadConfig() if err != nil { return err } delete(m, name) - return WriteConfig(m) + return pkgConfig.WriteConfig(constants.ConfigFile, m) } diff --git a/cmd/minikube/cmd/config/unset_test.go b/cmd/minikube/cmd/config/unset_test.go index 07f3aebbbf..c26a05028f 100644 --- a/cmd/minikube/cmd/config/unset_test.go +++ b/cmd/minikube/cmd/config/unset_test.go @@ -16,7 +16,11 @@ limitations under the License. package config -import "testing" +import ( + "testing" + + "k8s.io/minikube/pkg/minikube/config" +) func TestUnsetConfig(t *testing.T) { propName := "cpus" @@ -25,8 +29,23 @@ func TestUnsetConfig(t *testing.T) { if err != nil { t.Errorf("Failed to set the property %q", propName) } - err = unset(propName) + + cpus, err := config.Get("cpus") + if err != nil { + t.Errorf("Failed to read config %q", err) + } + + if cpus != propValue { + t.Errorf("Expected cpus to be %s but got %s", propValue, cpus) + } + + err = Unset(propName) if err != nil { t.Errorf("Failed to unset property %q", err) } + + _, err = config.Get("cpus") + if err != config.ErrKeyNotFound { + t.Errorf("Expected error %q but got %q", config.ErrKeyNotFound, err) + } } diff --git a/cmd/minikube/cmd/config/util.go b/cmd/minikube/cmd/config/util.go index 4b082bf2d6..18c0b5cd8f 100644 --- a/cmd/minikube/cmd/config/util.go +++ b/cmd/minikube/cmd/config/util.go @@ -27,10 +27,10 @@ import ( "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/storageclass" ) @@ -130,7 +130,7 @@ func EnableOrDisableAddon(name string, val string) error { cfg, err := config.Load() if err != nil && !os.IsNotExist(err) { - exit.WithCode(exit.Data, "Unable to load config: %v", err) + exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err}) } data := assets.GenerateTemplateData(cfg.KubernetesConfig) @@ -158,7 +158,7 @@ func enableOrDisableAddonInternal(addon *assets.Addon, cmd command.Runner, data var err error // check addon status before enabling/disabling it if err := isAddonAlreadySet(addon, enable); err != nil { - console.ErrStyle(console.Conflict, "%v", err) + out.ErrT(out.Conflict, "{{.error}}", out.V{"error": err}) os.Exit(0) } diff --git a/cmd/minikube/cmd/config/util_test.go b/cmd/minikube/cmd/config/util_test.go index 8e3e78ce11..0f0cf189c8 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": constants.DriverKvmOld, + "vm-driver": constants.DriverKvm2, "cpus": 12, "show-libmachine-logs": true, } diff --git a/cmd/minikube/cmd/config/validations.go b/cmd/minikube/cmd/config/validations.go index dedd468b16..aa6ca13ae5 100644 --- a/cmd/minikube/cmd/config/validations.go +++ b/cmd/minikube/cmd/config/validations.go @@ -28,9 +28,9 @@ import ( "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/minikube/out" ) // containerdOnlyMsg is the message shown when a containerd-only addon is enabled @@ -55,7 +55,7 @@ func IsValidDriver(string, driver string) error { // RequiresRestartMsg returns the "requires restart" message func RequiresRestartMsg(string, string) error { - console.OutStyle(console.WarningType, "These changes will take effect upon a minikube delete and then a minikube start") + out.T(out.WarningType, "These changes will take effect upon a minikube delete and then a minikube start") return nil } diff --git a/cmd/minikube/cmd/dashboard.go b/cmd/minikube/cmd/dashboard.go index 4d48264108..addb6b12b9 100644 --- a/cmd/minikube/cmd/dashboard.go +++ b/cmd/minikube/cmd/dashboard.go @@ -35,9 +35,9 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/cluster" pkg_config "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "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/minikube/service" "k8s.io/minikube/pkg/util" @@ -58,7 +58,7 @@ var dashboardCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { cc, err := pkg_config.Load() if err != nil && !os.IsNotExist(err) { - console.ErrLn("Error loading profile config: %v", err) + exit.WithError("Error loading profile config", err) } api, err := machine.NewAPIClient() @@ -76,8 +76,7 @@ var dashboardCmd = &cobra.Command{ if _, err = api.Load(pkg_config.GetMachineName()); err != nil { switch err := errors.Cause(err).(type) { case mcnerror.ErrHostDoesNotExist: - console.OutStyle(console.Meh, "%q cluster does not exist", pkg_config.GetMachineName()) - os.Exit(exit.Unavailable) + exit.WithCodeT(exit.Unavailable, "{{.name}} cluster does not exist", out.V{"name": pkg_config.GetMachineName()}) default: exit.WithError("Error getting cluster", err) } @@ -90,7 +89,7 @@ var dashboardCmd = &cobra.Command{ kubectl, err := exec.LookPath("kubectl") if err != nil { - exit.WithCode(exit.NoInput, "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/") + 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/") } cluster.EnsureMinikubeRunningOrExit(api, 1) @@ -100,7 +99,7 @@ var dashboardCmd = &cobra.Command{ dashboardStatus, _ := dashboardAddon.IsEnabled() if !dashboardStatus { // Send status messages to stderr for folks re-using this output. - console.ErrStyle(console.Enabling, "Enabling dashboard ...") + out.ErrT(out.Enabling, "Enabling dashboard ...") // Enable the dashboard add-on err = configcmd.Set("dashboard", "true") if err != nil { @@ -110,29 +109,29 @@ var dashboardCmd = &cobra.Command{ ns := "kube-system" svc := "kubernetes-dashboard" - console.ErrStyle(console.Verifying, "Verifying dashboard health ...") + out.ErrT(out.Verifying, "Verifying dashboard health ...") if err = util.RetryAfter(180, func() error { return service.CheckService(ns, svc) }, 1*time.Second); err != nil { - exit.WithCode(exit.Unavailable, "%s:%s is not running: %v", ns, svc, err) + exit.WithCodeT(exit.Unavailable, "dashboard service is not running: {{.error}}", out.V{"error": err}) } - console.ErrStyle(console.Launch, "Launching proxy ...") + out.ErrT(out.Launch, "Launching proxy ...") p, hostPort, err := kubectlProxy(kubectl) if err != nil { exit.WithError("kubectl proxy", err) } url := dashboardURL(hostPort, ns, svc) - console.ErrStyle(console.Verifying, "Verifying proxy health ...") + out.ErrT(out.Verifying, "Verifying proxy health ...") if err = util.RetryAfter(60, func() error { return checkURL(url) }, 1*time.Second); err != nil { - exit.WithCode(exit.Unavailable, "%s is not responding properly: %v", url, err) + exit.WithCodeT(exit.Unavailable, "{{.url}} is not accessible: {{.error}}", out.V{"url": url, "error": err}) } if dashboardURLMode { - console.OutLn(url) + out.Ln(url) } else { - console.ErrStyle(console.Celebrate, "Opening %s in your default browser...", url) + out.ErrT(out.Celebrate, "Opening %s in your default browser...", out.V{"url": url}) if err = browser.OpenURL(url); err != nil { - console.Failure("failed to open browser: %v", err) + exit.WithCodeT(exit.Software, "failed to open browser: {{.error}}", out.V{"error": err}) } } @@ -229,5 +228,4 @@ func checkURL(url string) error { func init() { dashboardCmd.Flags().BoolVar(&dashboardURLMode, "url", false, "Display dashboard URL instead of opening a browser") - RootCmd.AddCommand(dashboardCmd) } diff --git a/cmd/minikube/cmd/delete.go b/cmd/minikube/cmd/delete.go index 8b4f396726..d94a6c3a3b 100644 --- a/cmd/minikube/cmd/delete.go +++ b/cmd/minikube/cmd/delete.go @@ -28,10 +28,10 @@ import ( cmdUtil "k8s.io/minikube/cmd/util" "k8s.io/minikube/pkg/minikube/cluster" pkg_config "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" pkgutil "k8s.io/minikube/pkg/util" ) @@ -47,7 +47,7 @@ associated files.`, // runDelete handles the executes the flow of "minikube delete" func runDelete(cmd *cobra.Command, args []string) { if len(args) > 0 { - exit.Usage("usage: minikube delete") + exit.UsageT("usage: minikube delete") } profile := viper.GetString(pkg_config.MachineProfile) api, err := machine.NewAPIClient() @@ -58,7 +58,7 @@ func runDelete(cmd *cobra.Command, args []string) { cc, err := pkg_config.Load() if err != nil && !os.IsNotExist(err) { - console.ErrLn("Error loading profile config: %v", err) + out.ErrT(out.Sad, "Error loading profile config: {{.error}}", out.V{"name": profile}) } // In the case of "none", we want to uninstall Kubernetes as there is no VM to delete @@ -69,41 +69,41 @@ func runDelete(cmd *cobra.Command, args []string) { if err = cluster.DeleteHost(api); err != nil { switch err := errors.Cause(err).(type) { case mcnerror.ErrHostDoesNotExist: - console.OutStyle(console.Meh, "%q cluster does not exist", profile) + out.T(out.Meh, `"{{.name}}" cluster does not exist`, out.V{"name": profile}) default: exit.WithError("Failed to delete cluster", err) } } if err := cmdUtil.KillMountProcess(); err != nil { - console.Fatal("Failed to kill mount process: %v", err) + out.FatalT("Failed to kill mount process: {{.error}}", out.V{"error": err}) } if err := os.RemoveAll(constants.GetProfilePath(viper.GetString(pkg_config.MachineProfile))); err != nil { if os.IsNotExist(err) { - console.OutStyle(console.Meh, "%q profile does not exist", profile) + out.T(out.Meh, `"{{.profile_name}}" profile does not exist`, out.V{"profile_name": profile}) os.Exit(0) } exit.WithError("Failed to remove profile", err) } - console.OutStyle(console.Crushed, "The %q cluster has been deleted.", profile) + out.T(out.Crushed, `The "{{.cluster_name}}" cluster has been deleted.`, out.V{"cluster_name": profile}) machineName := pkg_config.GetMachineName() if err := pkgutil.DeleteKubeConfigContext(constants.KubeconfigPath, machineName); err != nil { exit.WithError("update config", err) } -} -func uninstallKubernetes(api libmachine.API, kc pkg_config.KubernetesConfig, bsName string) { - console.OutStyle(console.Resetting, "Uninstalling Kubernetes %s using %s ...", kc.KubernetesVersion, bsName) - clusterBootstrapper, err := GetClusterBootstrapper(api, bsName) - if err != nil { - console.ErrLn("Unable to get bootstrapper: %v", err) - } else if err = clusterBootstrapper.DeleteCluster(kc); err != nil { - console.ErrLn("Failed to delete cluster: %v", err) + if err := cmdcfg.Unset(pkg_config.MachineProfile); err != nil { + exit.WithError("unset minikube profile", err) } } -func init() { - RootCmd.AddCommand(deleteCmd) +func uninstallKubernetes(api libmachine.API, kc pkg_config.KubernetesConfig, bsName string) { + out.T(out.Resetting, "Uninstalling Kubernetes {{.kubernetes_version}} using {{.bootstrapper_name}} ...", out.V{"kubernetes_version": kc.KubernetesVersion, "bootstrapper_name": bsName}) + clusterBootstrapper, err := getClusterBootstrapper(api, bsName) + if err != nil { + out.ErrT(out.Empty, "Unable to get bootstrapper: {{.error}}", out.V{"error": err}) + } else if err = clusterBootstrapper.DeleteCluster(kc); err != nil { + out.ErrT(out.Empty, "Failed to delete cluster: {{.error}}", out.V{"error": err}) + } } diff --git a/cmd/minikube/cmd/env.go b/cmd/minikube/cmd/env.go index cf4d669178..8157c35e1b 100644 --- a/cmd/minikube/cmd/env.go +++ b/cmd/minikube/cmd/env.go @@ -344,21 +344,21 @@ var dockerEnvCmd = &cobra.Command{ exit.WithError("Error getting host", err) } if host.Driver.DriverName() == constants.DriverNone { - exit.Usage(`'none' driver does not support 'minikube docker-env' command`) + exit.UsageT(`'none' driver does not support 'minikube docker-env' command`) } hostSt, err := cluster.GetHostStatus(api) if err != nil { exit.WithError("Error getting host status", err) } if hostSt != state.Running.String() { - exit.WithCode(exit.Unavailable, `The docker host is currently not running`) + exit.WithCodeT(exit.Unavailable, `The docker host is currently not running`) } docker, err := GetDockerActive(host) if err != nil { exit.WithError("Error getting service status", err) } if !docker { - exit.WithCode(exit.Unavailable, `The docker service is currently not active`) + exit.WithCodeT(exit.Unavailable, `The docker service is currently not active`) } var shellCfg *ShellConfig @@ -382,7 +382,6 @@ var dockerEnvCmd = &cobra.Command{ } func init() { - RootCmd.AddCommand(dockerEnvCmd) defaultShellDetector = &LibmachineShellDetector{} defaultNoProxyGetter = &EnvNoProxyGetter{} dockerEnvCmd.Flags().BoolVar(&noProxy, "no-proxy", false, "Add machine IP to NO_PROXY environment variable") diff --git a/cmd/minikube/cmd/env_test.go b/cmd/minikube/cmd/env_test.go index 7bc8dfb562..468df82196 100644 --- a/cmd/minikube/cmd/env_test.go +++ b/cmd/minikube/cmd/env_test.go @@ -20,7 +20,6 @@ import ( "reflect" "testing" - "github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine/host" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" @@ -71,7 +70,7 @@ func newShellCfg(shell, prefix, suffix, delim string) *ShellConfig { func TestShellCfgSet(t *testing.T) { var tests = []struct { description string - api libmachine.API + api *tests.MockAPI shell string noProxyVar string noProxyValue string @@ -236,7 +235,7 @@ func TestShellCfgSet(t *testing.T) { defaultShellDetector = &FakeShellDetector{test.shell} defaultNoProxyGetter = &FakeNoProxyGetter{test.noProxyVar, test.noProxyValue} noProxy = test.noProxyFlag - + test.api.T = t shellCfg, err := shellCfgSet(test.api) if !reflect.DeepEqual(shellCfg, test.expectedShellCfg) { t.Errorf("Shell cfgs differ: expected %+v, \n\n got %+v", test.expectedShellCfg, shellCfg) diff --git a/cmd/minikube/cmd/ip.go b/cmd/minikube/cmd/ip.go index a066959a41..83ff5575c4 100644 --- a/cmd/minikube/cmd/ip.go +++ b/cmd/minikube/cmd/ip.go @@ -21,9 +21,9 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" ) // ipCmd represents the ip command @@ -42,7 +42,7 @@ var ipCmd = &cobra.Command{ if err != nil { switch err := errors.Cause(err).(type) { case mcnerror.ErrHostDoesNotExist: - exit.WithCode(exit.NoInput, "%q host does not exist, unable to show an IP", config.GetMachineName()) + exit.WithCodeT(exit.NoInput, `"{{.profile_name}}" host does not exist, unable to show an IP`, out.V{"profile_name": config.GetMachineName()}) default: exit.WithError("Error getting host", err) } @@ -51,10 +51,6 @@ var ipCmd = &cobra.Command{ if err != nil { exit.WithError("Error getting IP", err) } - console.OutLn(ip) + out.Ln(ip) }, } - -func init() { - RootCmd.AddCommand(ipCmd) -} diff --git a/cmd/minikube/cmd/kubectl.go b/cmd/minikube/cmd/kubectl.go index 5cf1424879..a1b1cc808f 100644 --- a/cmd/minikube/cmd/kubectl.go +++ b/cmd/minikube/cmd/kubectl.go @@ -26,10 +26,10 @@ import ( "github.com/golang/glog" "github.com/spf13/cobra" pkg_config "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" ) // kubectlCmd represents the kubectl command @@ -50,7 +50,7 @@ kubectl get pods --namespace kube-system`, cc, err := pkg_config.Load() if err != nil && !os.IsNotExist(err) { - console.ErrLn("Error loading profile config: %v", err) + out.ErrLn("Error loading profile config: %v", err) } binary := "kubectl" @@ -86,7 +86,3 @@ kubectl get pods --namespace kube-system`, } }, } - -func init() { - RootCmd.AddCommand(kubectlCmd) -} diff --git a/cmd/minikube/cmd/logs.go b/cmd/minikube/cmd/logs.go index 2df75e4e6a..7924ba7c24 100644 --- a/cmd/minikube/cmd/logs.go +++ b/cmd/minikube/cmd/logs.go @@ -66,7 +66,7 @@ var logsCmd = &cobra.Command{ if err != nil { exit.WithError("command runner", err) } - bs, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper)) + bs, err := getClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper)) if err != nil { exit.WithError("Error getting cluster bootstrapper", err) } @@ -97,6 +97,5 @@ var logsCmd = &cobra.Command{ 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", 50, "Number of lines back to go within the log") - RootCmd.AddCommand(logsCmd) + logsCmd.Flags().IntVarP(&numberOfLines, "length", "n", 30, "Number of lines back to go within the log") } diff --git a/cmd/minikube/cmd/mount.go b/cmd/minikube/cmd/mount.go index a91d38a266..942cd98460 100644 --- a/cmd/minikube/cmd/mount.go +++ b/cmd/minikube/cmd/mount.go @@ -17,6 +17,7 @@ limitations under the License. package cmd import ( + "fmt" "net" "os" "os/signal" @@ -30,10 +31,10 @@ import ( cmdUtil "k8s.io/minikube/cmd/util" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/third_party/go9p/ufs" ) @@ -68,25 +69,25 @@ var mountCmd = &cobra.Command{ } if len(args) != 1 { - exit.Usage(`Please specify the directory to be mounted: + exit.UsageT(`Please specify the directory to be mounted: minikube mount : (example: "/host-home:/vm-home")`) } mountString := args[0] idx := strings.LastIndex(mountString, ":") if idx == -1 { // no ":" was present - exit.Usage(`mount argument %q must be in form: :`, mountString) + exit.UsageT(`mount argument "{{.value}}" must be in form: :`, out.V{"value": mountString}) } hostPath := mountString[:idx] vmPath := mountString[idx+1:] if _, err := os.Stat(hostPath); err != nil { if os.IsNotExist(err) { - exit.WithCode(exit.NoInput, "Cannot find directory %s for mount", hostPath) + exit.WithCodeT(exit.NoInput, "Cannot find directory {{.path}} for mount", out.V{"path": hostPath}) } else { exit.WithError("stat failed", err) } } if len(vmPath) == 0 || !strings.HasPrefix(vmPath, "/") { - exit.Usage("Target directory %q must be an absolute path", vmPath) + exit.UsageT("Target directory {{.path}} must be an absolute path", out.V{"path": vmPath}) } var debugVal int if glog.V(1) { @@ -103,7 +104,7 @@ var mountCmd = &cobra.Command{ exit.WithError("Error loading api", err) } if host.Driver.DriverName() == constants.DriverNone { - exit.Usage(`'none' driver does not support 'minikube mount' command`) + exit.UsageT(`'none' driver does not support 'minikube mount' command`) } var ip net.IP if mountIP == "" { @@ -114,7 +115,7 @@ var mountCmd = &cobra.Command{ } else { ip = net.ParseIP(mountIP) if ip == nil { - exit.WithCode(exit.Data, "error parsing the input ip address for mount") + exit.WithCodeT(exit.Data, "error parsing the input ip address for mount") } } port, err := cmdUtil.GetPort() @@ -142,29 +143,27 @@ var mountCmd = &cobra.Command{ cfg.Options[parts[0]] = parts[1] } - console.OutStyle(console.Mounting, "Mounting host path %s into VM as %s ...", hostPath, vmPath) - console.OutStyle(console.MountOptions, "Mount options:") - console.OutStyle(console.Option, "Type: %s", cfg.Type) - console.OutStyle(console.Option, "UID: %s", cfg.UID) - console.OutStyle(console.Option, "GID: %s", cfg.GID) - console.OutStyle(console.Option, "Version: %s", cfg.Version) - console.OutStyle(console.Option, "MSize: %d", cfg.MSize) - console.OutStyle(console.Option, "Mode: %o (%s)", cfg.Mode, cfg.Mode) - console.OutStyle(console.Option, "Options: %s", cfg.Options) + out.T(out.Mounting, "Mounting host path {{.sourcePath}} into VM as {{.destinationPath}} ...", out.V{"sourcePath": hostPath, "destinationPath": vmPath}) + out.T(out.Option, "Mount type: {{.name}}", out.V{"type": cfg.Type}) + out.T(out.Option, "User ID: {{.userID}}", out.V{"userID": cfg.UID}) + out.T(out.Option, "Group ID: {{.groupID}}", out.V{"groupID": cfg.GID}) + out.T(out.Option, "Version: {{.version}}", out.V{"version": cfg.Version}) + out.T(out.Option, "Message Size: {{.size}}", out.V{"size": cfg.MSize}) + out.T(out.Option, "Permissions: {{.octalMode}} ({{.writtenMode}})", out.V{"octalMode": fmt.Sprintf("%o", cfg.Mode), "writtenMode": cfg.Mode}) + out.T(out.Option, "Options: {{.options}}", out.V{"options": cfg.Options}) // An escape valve to allow future hackers to try NFS, VirtFS, or other FS types. if !supportedFilesystems[cfg.Type] { - console.OutLn("") - console.OutStyle(console.WarningType, "%s is not yet a supported filesystem. We will try anyways!", cfg.Type) + out.T(out.WarningType, "{{.type}} is not yet a supported filesystem. We will try anyways!", out.V{"type": cfg.Type}) } var wg sync.WaitGroup if cfg.Type == nineP { wg.Add(1) go func() { - console.OutStyle(console.Fileserver, "Userspace file server: ") + out.T(out.Fileserver, "Userspace file server: ") ufs.StartServer(net.JoinHostPort(ip.String(), strconv.Itoa(port)), debugVal, hostPath) - console.OutStyle(console.Stopped, "Userspace file server is shutdown") + out.T(out.Stopped, "Userspace file server is shutdown") wg.Done() }() } @@ -180,12 +179,12 @@ var mountCmd = &cobra.Command{ signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { for sig := range c { - console.OutStyle(console.Unmount, "Unmounting %s ...", vmPath) + out.T(out.Unmount, "Unmounting {{.path}} ...", out.V{"path": vmPath}) err := cluster.Unmount(runner, vmPath) if err != nil { - console.ErrStyle(console.FailureType, "Failed unmount: %v", err) + out.ErrT(out.FailureType, "Failed unmount: {{.error}}", out.V{"error": err}) } - exit.WithCode(exit.Interrupted, "Exiting due to %s signal", sig) + exit.WithCodeT(exit.Interrupted, "Received {{.name}} signal", out.V{"name": sig}) } }() @@ -193,9 +192,9 @@ var mountCmd = &cobra.Command{ if err != nil { exit.WithError("mount failed", err) } - console.OutStyle(console.SuccessType, "Successfully mounted %s to %s", hostPath, vmPath) - console.OutLn("") - console.OutStyle(console.Notice, "NOTE: This process must stay alive for the mount to be accessible ...") + out.T(out.SuccessType, "Successfully mounted {{.sourcePath}} to {{.destinationPath}}", out.V{"sourcePath": hostPath, "destinationPath": vmPath}) + out.Ln("") + out.T(out.Notice, "NOTE: This process must stay alive for the mount to be accessible ...") wg.Wait() }, } @@ -210,5 +209,4 @@ func init() { mountCmd.Flags().UintVar(&mode, "mode", 0755, "File permissions used for the mount") mountCmd.Flags().StringSliceVar(&options, "options", []string{}, "Additional mount options, such as cache=fscache") mountCmd.Flags().IntVar(&mSize, "msize", constants.DefaultMsize, "The number of bytes to use for 9p packet payload") - RootCmd.AddCommand(mountCmd) } diff --git a/cmd/minikube/cmd/root.go b/cmd/minikube/cmd/root.go index 4c5566e8ee..07c42b58fd 100644 --- a/cmd/minikube/cmd/root.go +++ b/cmd/minikube/cmd/root.go @@ -30,6 +30,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" + "k8s.io/kubectl/pkg/util/templates" configCmd "k8s.io/minikube/cmd/minikube/cmd/config" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/bootstrapper/kubeadm" @@ -128,9 +129,66 @@ func setFlagsUsingViper() { func init() { 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(configCmd.Bootstrapper, "b", constants.DefaultClusterBootstrapper, "The name of the cluster bootstrapper that will set up the kubernetes cluster.") - RootCmd.AddCommand(configCmd.ConfigCmd) - RootCmd.AddCommand(configCmd.AddonsCmd) - RootCmd.AddCommand(configCmd.ProfileCmd) + + groups := templates.CommandGroups{ + { + Message: "Basic Commands:", + Commands: []*cobra.Command{ + startCmd, + statusCmd, + stopCmd, + deleteCmd, + dashboardCmd, + }, + }, + { + Message: "Images Commands:", + Commands: []*cobra.Command{ + dockerEnvCmd, + cacheCmd, + }, + }, + { + Message: "Configuration and Management Commands:", + Commands: []*cobra.Command{ + configCmd.AddonsCmd, + configCmd.ConfigCmd, + configCmd.ProfileCmd, + updateContextCmd, + }, + }, + { + Message: "Networking and Connectivity Commands:", + Commands: []*cobra.Command{ + serviceCmd, + tunnelCmd, + }, + }, + { + Message: "Advanced Commands:", + Commands: []*cobra.Command{ + mountCmd, + sshCmd, + kubectlCmd, + }, + }, + { + Message: "Troubleshooting Commands:", + Commands: []*cobra.Command{ + sshKeyCmd, + ipCmd, + logsCmd, + updateCheckCmd, + versionCmd, + }, + }, + } + groups.Add(RootCmd) + + // any not grouped command will show in Other Commands group. + RootCmd.AddCommand(completionCmd) + templates.ActsAsRootCommand(RootCmd, []string{"options"}, groups...) + pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) if err := viper.BindPFlags(RootCmd.PersistentFlags()); err != nil { exit.WithError("Unable to bind flags", err) @@ -170,8 +228,8 @@ func setupViper() { setFlagsUsingViper() } -// GetClusterBootstrapper returns a new bootstrapper for the cluster -func GetClusterBootstrapper(api libmachine.API, bootstrapperName string) (bootstrapper.Bootstrapper, error) { +// getClusterBootstrapper returns a new bootstrapper for the cluster +func getClusterBootstrapper(api libmachine.API, bootstrapperName string) (bootstrapper.Bootstrapper, error) { var b bootstrapper.Bootstrapper var err error switch bootstrapperName { diff --git a/cmd/minikube/cmd/service.go b/cmd/minikube/cmd/service.go index 84e8db0ae6..50c893cf64 100644 --- a/cmd/minikube/cmd/service.go +++ b/cmd/minikube/cmd/service.go @@ -55,7 +55,7 @@ var serviceCmd = &cobra.Command{ }, Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 || len(args) > 1 { - exit.Usage("You must specify a service name") + exit.UsageT("You must specify a service name") } svc := args[0] @@ -83,5 +83,4 @@ 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.") - RootCmd.AddCommand(serviceCmd) } diff --git a/cmd/minikube/cmd/service_list.go b/cmd/minikube/cmd/service_list.go index 9b5376d78d..ad1903a4b8 100644 --- a/cmd/minikube/cmd/service_list.go +++ b/cmd/minikube/cmd/service_list.go @@ -22,9 +22,9 @@ import ( "github.com/spf13/cobra" core "k8s.io/api/core/v1" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/service" ) @@ -43,8 +43,8 @@ var serviceListCmd = &cobra.Command{ defer api.Close() serviceURLs, err := service.GetServiceURLs(api, serviceListNamespace, serviceURLTemplate) if err != nil { - console.Fatal("Failed to get service URL: %v", err) - console.ErrStyle(console.Notice, "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.") + out.FatalT("Failed to get service URL: {{.error}}", out.V{"error": err}) + out.ErrT(out.Notice, "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.") os.Exit(exit.Unavailable) } diff --git a/cmd/minikube/cmd/ssh-key.go b/cmd/minikube/cmd/ssh-key.go index b1fb4e2717..981af193e3 100644 --- a/cmd/minikube/cmd/ssh-key.go +++ b/cmd/minikube/cmd/ssh-key.go @@ -21,8 +21,8 @@ import ( "github.com/spf13/cobra" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/out" ) // sshKeyCmd represents the sshKey command @@ -31,10 +31,6 @@ 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) { - console.OutLn(filepath.Join(constants.GetMinipath(), "machines", config.GetMachineName(), "id_rsa")) + out.Ln(filepath.Join(constants.GetMinipath(), "machines", config.GetMachineName(), "id_rsa")) }, } - -func init() { - RootCmd.AddCommand(sshKeyCmd) -} diff --git a/cmd/minikube/cmd/ssh.go b/cmd/minikube/cmd/ssh.go index e791f69330..b2610f25ee 100644 --- a/cmd/minikube/cmd/ssh.go +++ b/cmd/minikube/cmd/ssh.go @@ -22,10 +22,10 @@ import ( "github.com/spf13/cobra" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" ) // sshCmd represents the docker-ssh command @@ -44,18 +44,14 @@ var sshCmd = &cobra.Command{ exit.WithError("Error getting host", err) } if host.Driver.DriverName() == constants.DriverNone { - exit.Usage("'none' driver does not support 'minikube ssh' command") + exit.UsageT("'none' driver does not support 'minikube ssh' command") } err = cluster.CreateSSHShell(api, args) if err != nil { // This is typically due to a non-zero exit code, so no need for flourish. - console.ErrLn("ssh: %v", err) + out.ErrLn("ssh: %v", err) // It'd be nice if we could pass up the correct error code here :( os.Exit(exit.Failure) } }, } - -func init() { - RootCmd.AddCommand(sshCmd) -} diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 7920d575b6..6adab87604 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -41,6 +41,7 @@ import ( "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" + gopshost "github.com/shirou/gopsutil/host" "github.com/spf13/cobra" "github.com/spf13/viper" "golang.org/x/sync/errgroup" @@ -51,12 +52,12 @@ import ( "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/command" cfg "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/logs" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/proxy" pkgutil "k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/version" @@ -68,7 +69,6 @@ const ( cpus = "cpus" humanReadableDiskSize = "disk-size" vmDriver = "vm-driver" - xhyveDiskDriver = "xhyve-disk-driver" nfsSharesRoot = "nfs-shares-root" nfsShare = "nfs-share" kubernetesVersion = "kubernetes-version" @@ -102,6 +102,7 @@ const ( downloadOnly = "download-only" dnsProxy = "dns-proxy" hostDNSResolver = "host-dns-resolver" + waitUntilHealthy = "wait" ) var ( @@ -115,82 +116,163 @@ var ( ) func init() { - startCmd.Flags().Bool(keepContext, constants.DefaultKeepContext, "This will keep the existing kubectl context and will create a minikube context.") - startCmd.Flags().Bool(createMount, false, "This will start the mount daemon and automatically mount files into minikube") - startCmd.Flags().String(mountString, constants.DefaultMountDir+":"+constants.DefaultMountEndpoint, "The argument to pass the minikube mount command on start") - startCmd.Flags().Bool(disableDriverMounts, false, "Disables the filesystem mounts provided by the hypervisors (vboxfs, xhyve-9p)") - startCmd.Flags().String(isoURL, constants.DefaultISOURL, "Location of the minikube iso") - startCmd.Flags().String(vmDriver, constants.DefaultVMDriver, fmt.Sprintf("VM driver is one of: %v", constants.SupportedVMDrivers)) - startCmd.Flags().String(memory, constants.DefaultMemorySize, "Amount of RAM allocated to the minikube VM (format: [], where unit = b, k, m or g)") + initMinikubeFlags() + initKubernetesFlags() + initDriverFlags() + initNetworkingFlags() + if err := viper.BindPFlags(startCmd.Flags()); err != nil { + exit.WithError("unable to bind flags", err) + } + +} + +// initMinikubeFlags includes commandline flags for minikube. +func initMinikubeFlags() { + viper.SetEnvPrefix(constants.MinikubeEnvPrefix) + // Replaces '-' in flags with '_' in env variables + // e.g. iso-url => $ENVPREFIX_ISO_URL + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + viper.AutomaticEnv() + startCmd.Flags().Int(cpus, constants.DefaultCPUS, "Number of CPUs allocated to the minikube VM") + startCmd.Flags().String(memory, constants.DefaultMemorySize, "Amount of RAM allocated to the minikube VM (format: [], where unit = b, k, m or g)") startCmd.Flags().String(humanReadableDiskSize, constants.DefaultDiskSize, "Disk size allocated to the minikube VM (format: [], where unit = b, k, m or g)") - startCmd.Flags().String(hostOnlyCIDR, "192.168.99.1/24", "The CIDR to be used for the minikube VM (only supported with Virtualbox driver)") - startCmd.Flags().String(hypervVirtualSwitch, "", "The hyperv virtual switch name. Defaults to first found. (only supported with HyperV driver)") - startCmd.Flags().String(kvmNetwork, "default", "The KVM network name. (only supported with KVM driver)") - startCmd.Flags().String(kvmQemuURI, "qemu:///system", "The KVM QEMU connection URI. (works only with kvm2 driver on linux)") - startCmd.Flags().Bool(kvmGPU, false, "Enable experimental NVIDIA GPU support in minikube") - startCmd.Flags().Bool(kvmHidden, false, "Hide the hypervisor signature from the guest in minikube") - startCmd.Flags().String(xhyveDiskDriver, "ahci-hd", "The disk driver to use [ahci-hd|virtio-blk] (only supported with xhyve driver)") - startCmd.Flags().StringSlice(nfsShare, []string{}, "Local folders to share with Guest via NFS mounts (Only supported on with hyperkit now)") - startCmd.Flags().String(nfsSharesRoot, "/nfsshares", "Where to root the NFS Shares (defaults to /nfsshares, only supported with hyperkit now)") - startCmd.Flags().StringArrayVar(&dockerEnv, "docker-env", nil, "Environment variables to pass to the Docker daemon. (format: key=value)") - startCmd.Flags().StringArrayVar(&dockerOpt, "docker-opt", nil, "Specify arbitrary flags to pass to the Docker daemon. (format: key=value)") - startCmd.Flags().Int(apiServerPort, pkgutil.APIServerPort, "The apiserver listening port") - startCmd.Flags().String(apiServerName, constants.APIServerName, "The apiserver name which is used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine") - startCmd.Flags().StringArrayVar(&apiServerNames, "apiserver-names", nil, "A set of apiserver names which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine") - startCmd.Flags().IPSliceVar(&apiServerIPs, "apiserver-ips", nil, "A set of apiserver IP Addresses which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine") - startCmd.Flags().String(dnsDomain, constants.ClusterDNSDomain, "The cluster dns domain name used in the kubernetes cluster") - startCmd.Flags().String(serviceCIDR, pkgutil.DefaultServiceCIDR, "The CIDR to be used for service cluster IPs.") - startCmd.Flags().StringSliceVar(&insecureRegistry, "insecure-registry", nil, "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.") - startCmd.Flags().StringSliceVar(®istryMirror, "registry-mirror", nil, "Registry mirrors to pass to the Docker daemon") - startCmd.Flags().String(imageRepository, "", "Alternative image repository to pull docker images from. This can be used when you have limited access to gcr.io. Set it to \"auto\" to let minikube decide one for you. For Chinese mainland users, you may use local gcr.io mirrors such as registry.cn-hangzhou.aliyuncs.com/google_containers") - startCmd.Flags().String(imageMirrorCountry, "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn") - startCmd.Flags().String(containerRuntime, "docker", "The container runtime to be used (docker, crio, containerd)") - startCmd.Flags().String(criSocket, "", "The cri socket path to be used") - startCmd.Flags().String(kubernetesVersion, constants.DefaultKubernetesVersion, "The kubernetes version that the minikube VM will use (ex: v1.2.3)") - startCmd.Flags().String(networkPlugin, "", "The name of the network plugin") - startCmd.Flags().Bool(enableDefaultCNI, false, "Enable the default CNI plugin (/etc/cni/net.d/k8s.conf). Used in conjunction with \"--network-plugin=cni\"") - startCmd.Flags().String(featureGates, "", "A set of key=value pairs that describe feature gates for alpha/experimental features.") 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(keepContext, constants.DefaultKeepContext, "This will keep the existing kubectl context and will create a minikube context.") + startCmd.Flags().String(containerRuntime, "docker", "The container runtime to be used (docker, crio, containerd)") + startCmd.Flags().Bool(createMount, false, "This will start the mount daemon and automatically mount files into minikube") + startCmd.Flags().String(mountString, constants.DefaultMountDir+":"+constants.DefaultMountEndpoint, "The argument to pass the minikube mount command on start") + startCmd.Flags().String(criSocket, "", "The cri socket path to be used") + startCmd.Flags().String(networkPlugin, "", "The name of the network plugin") + startCmd.Flags().Bool(enableDefaultCNI, false, "Enable the default CNI plugin (/etc/cni/net.d/k8s.conf). Used in conjunction with \"--network-plugin=cni\"") + startCmd.Flags().Bool(waitUntilHealthy, true, "Wait until Kubernetes core services are healthy before exiting") +} + +// initKubernetesFlags inits the commandline flags for kubernetes related options +func initKubernetesFlags() { + startCmd.Flags().String(kubernetesVersion, constants.DefaultKubernetesVersion, "The kubernetes version that the minikube VM will use (ex: v1.2.3)") startCmd.Flags().Var(&extraOptions, "extra-config", `A set of key=value pairs that describe configuration that may be passed to different components. The key should be '.' separated, and the first part before the dot is the component to apply the configuration to. Valid components are: kubelet, kubeadm, apiserver, controller-manager, etcd, proxy, scheduler Valid kubeadm parameters: `+fmt.Sprintf("%s, %s", strings.Join(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmCmdParam], ", "), strings.Join(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmConfigParam], ","))) - startCmd.Flags().String(uuid, "", "Provide VM UUID to restore MAC address (only supported with Hyperkit driver).") - startCmd.Flags().String(vpnkitSock, "", "Location of the VPNKit socket used for networking. If empty, disables Hyperkit VPNKitSock, if 'auto' uses Docker for Mac VPNKit connection, otherwise uses the specified VSock.") - startCmd.Flags().StringSlice(vsockPorts, []string{}, "List of guest VSock ports that should be exposed as sockets on the host (Only supported on with hyperkit now).") - startCmd.Flags().Bool(noVTXCheck, false, "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox)") + startCmd.Flags().String(featureGates, "", "A set of key=value pairs that describe feature gates for alpha/experimental features.") + startCmd.Flags().String(dnsDomain, constants.ClusterDNSDomain, "The cluster dns domain name used in the kubernetes cluster") + startCmd.Flags().Int(apiServerPort, pkgutil.APIServerPort, "The apiserver listening port") + startCmd.Flags().String(apiServerName, constants.APIServerName, "The apiserver name which is used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine") + startCmd.Flags().StringArrayVar(&apiServerNames, "apiserver-names", nil, "A set of apiserver names which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine") + startCmd.Flags().IPSliceVar(&apiServerIPs, "apiserver-ips", nil, "A set of apiserver IP Addresses which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine") +} + +// initDriverFlags inits the commandline flags for vm drivers +func initDriverFlags() { + startCmd.Flags().String(vmDriver, constants.DefaultVMDriver, fmt.Sprintf("VM driver is one of: %v", constants.SupportedVMDrivers)) + + // kvm2 + startCmd.Flags().String(kvmNetwork, "default", "The KVM network name. (only supported with KVM driver)") + startCmd.Flags().String(kvmQemuURI, "qemu:///system", "The KVM QEMU connection URI. (works only with kvm2 driver on linux)") + startCmd.Flags().Bool(kvmGPU, false, "Enable experimental NVIDIA GPU support in minikube") + startCmd.Flags().Bool(kvmHidden, false, "Hide the hypervisor signature from the guest in minikube") + + // virtualbox + startCmd.Flags().String(hostOnlyCIDR, "192.168.99.1/24", "The CIDR to be used for the minikube VM (only supported with Virtualbox driver)") startCmd.Flags().Bool(dnsProxy, false, "Enable proxy for NAT DNS requests (virtualbox)") startCmd.Flags().Bool(hostDNSResolver, true, "Enable host resolver for NAT DNS requests (virtualbox)") - if err := viper.BindPFlags(startCmd.Flags()); err != nil { - exit.WithError("unable to bind flags", err) - } - RootCmd.AddCommand(startCmd) + startCmd.Flags().Bool(noVTXCheck, false, "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox)") + + // hyperkit + startCmd.Flags().StringSlice(vsockPorts, []string{}, "List of guest VSock ports that should be exposed as sockets on the host (Only supported on with hyperkit now).") + startCmd.Flags().String(uuid, "", "Provide VM UUID to restore MAC address (only supported with Hyperkit driver).") + startCmd.Flags().String(vpnkitSock, "", "Location of the VPNKit socket used for networking. If empty, disables Hyperkit VPNKitSock, if 'auto' uses Docker for Mac VPNKit connection, otherwise uses the specified VSock.") + startCmd.Flags().StringSlice(nfsShare, []string{}, "Local folders to share with Guest via NFS mounts (Only supported on with hyperkit now)") + startCmd.Flags().String(nfsSharesRoot, "/nfsshares", "Where to root the NFS Shares (defaults to /nfsshares, only supported with hyperkit now)") + + // hyperv + startCmd.Flags().String(hypervVirtualSwitch, "", "The hyperv virtual switch name. Defaults to first found. (only supported with HyperV driver)") +} + +// initNetworkingFlags inits the commandline flags for connectivity related flags for start +func initNetworkingFlags() { + startCmd.Flags().StringSliceVar(&insecureRegistry, "insecure-registry", nil, "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.") + startCmd.Flags().StringSliceVar(®istryMirror, "registry-mirror", nil, "Registry mirrors to pass to the Docker daemon") + startCmd.Flags().String(imageRepository, "", "Alternative image repository to pull docker images from. This can be used when you have limited access to gcr.io. Set it to \"auto\" to let minikube decide one for you. For Chinese mainland users, you may use local gcr.io mirrors such as registry.cn-hangzhou.aliyuncs.com/google_containers") + startCmd.Flags().String(imageMirrorCountry, "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn") + startCmd.Flags().String(serviceCIDR, pkgutil.DefaultServiceCIDR, "The CIDR to be used for service cluster IPs.") + startCmd.Flags().StringArrayVar(&dockerEnv, "docker-env", nil, "Environment variables to pass to the Docker daemon. (format: key=value)") + startCmd.Flags().StringArrayVar(&dockerOpt, "docker-opt", nil, "Specify arbitrary flags to pass to the Docker daemon. (format: key=value)") } // startCmd represents the start command var startCmd = &cobra.Command{ Use: "start", Short: "Starts a local kubernetes cluster", - Long: `Starts a local kubernetes cluster using VM. This command -assumes you have already installed one of the VM drivers: virtualbox/parallels/vmwarefusion/kvm/xhyve/hyperv.`, - Run: runStart, + Long: "Starts a local kubernetes cluster", + Run: runStart, +} + +// platform generates a user-readable platform message +func platform() string { + var s strings.Builder + + // Show the distro version if possible + hi, err := gopshost.Info() + if err == nil { + s.WriteString(fmt.Sprintf("%s %s", strings.Title(hi.Platform), hi.PlatformVersion)) + glog.Infof("hostinfo: %+v", hi) + } else { + glog.Warningf("gopshost.Info returned error: %v", err) + s.WriteString(runtime.GOOS) + } + + vsys, vrole, err := gopshost.Virtualization() + if err != nil { + glog.Warningf("gopshost.Virtualization returned error: %v", err) + } else { + glog.Infof("virtualization: %s %s", vsys, vrole) + } + + // This environment is exotic, let's output a bit more. + if vrole == "guest" || runtime.GOARCH != "amd64" { + s.WriteString(fmt.Sprintf(" (%s/%s)", vsys, runtime.GOARCH)) + } + return s.String() } // runStart handles the executes the flow of "minikube start" func runStart(cmd *cobra.Command, args []string) { - console.OutT(console.Happy, "minikube {{.version}} on {{.os}} ({{.arch}})", console.Arg{"version": version.GetVersion(), "os": runtime.GOOS, "arch": runtime.GOARCH}) - validateConfig() - - validateUser() - - oldConfig, err := cfg.Load() - if err != nil && !os.IsNotExist(err) { - exit.WithCode(exit.Data, "Unable to load config: %v", err) + prefix := "" + if viper.GetString(cfg.MachineProfile) != constants.DefaultMachineName { + prefix = fmt.Sprintf("[%s] ", viper.GetString(cfg.MachineProfile)) } - k8sVersion, isUpgrade := validateKubernetesVersions(oldConfig) + out.T(out.Happy, "{{.prefix}}minikube {{.version}} on {{.platform}}", out.V{"prefix": prefix, "version": version.GetVersion(), "platform": platform()}) + + // if --registry-mirror specified when run minikube start, + // take arg precedence over MINIKUBE_REGISTRY_MIRROR + // actually this is a hack, because viper 1.0.0 can assign env to variable if StringSliceVar + // and i can't update it to 1.4.0, it affects too much code + // other types (like String, Bool) of flag works, so imageRepository, imageMirrorCountry + // can be configured as MINIKUBE_IMAGE_REPOSITORY and IMAGE_MIRROR_COUNTRY + // this should be updated to documentation + if len(registryMirror) == 0 { + registryMirror = viper.GetStringSlice("registry_mirror") + } + + vmDriver := viper.GetString(vmDriver) + if err := cmdcfg.IsValidDriver(runtime.GOOS, vmDriver); err != nil { + exit.WithCodeT( + exit.Failure, + "The driver '{{.driver}}' is not supported on {{.os}}", + out.V{"driver": vmDriver, "os": runtime.GOOS}, + ) + } + + validateConfig() + validateUser() + validateDriverVersion(viper.GetString(vmDriver)) + + k8sVersion, isUpgrade := getKubernetesVersion() config, err := generateConfig(cmd, k8sVersion) if err != nil { exit.WithError("Failed to generate config", err) @@ -200,7 +282,7 @@ func runStart(cmd *cobra.Command, args []string) { downloadISO(config) // With "none", images are persistently stored in Docker, so internal caching isn't necessary. - skipCache(config) + skipCache(&config) // Now that the ISO is downloaded, pull images in the background while the VM boots. var cacheGroup errgroup.Group @@ -208,76 +290,89 @@ func runStart(cmd *cobra.Command, args []string) { // Abstraction leakage alert: startHost requires the config to be saved, to satistfy pkg/provision/buildroot. // Hence, saveConfig must be called before startHost, and again afterwards when we know the IP. - if err := saveConfig(config); err != nil { + if err := saveConfig(&config); err != nil { exit.WithError("Failed to save config", err) } - validateDriverVersion(viper.GetString(vmDriver)) + // exits here in case of --download-only option. + handleDownloadOnly(&cacheGroup, k8sVersion) + mRunner, preExists, machineAPI, host := startMachine(&config) + defer machineAPI.Close() + // configure the runtime (docker, containerd, crio) + cr := configureRuntimes(mRunner) + showVersionInfo(k8sVersion, cr) + waitCacheImages(&cacheGroup) + // setup kube adm and certs and return bootstrapperx + bs := setupKubeAdm(machineAPI, config.KubernetesConfig) + // The kube config must be update must come before bootstrapping, otherwise health checks may use a stale IP + kubeconfig := updateKubeConfig(host, &config) + // pull images or restart cluster + bootstrapCluster(bs, cr, mRunner, config.KubernetesConfig, preExists, isUpgrade) + configureMounts() + if err = loadCachedImagesInConfigFile(); err != nil { + out.T(out.FailureType, "Unable to load cached images from config file.") + } + // special ops for none driver, like change minikube directory. + prepareNone(viper.GetString(vmDriver)) + if viper.GetBool(waitUntilHealthy) { + if err := bs.WaitCluster(config.KubernetesConfig); err != nil { + exit.WithError("Wait failed", err) + } + } + showKubectlConnectInfo(kubeconfig) + +} + +func handleDownloadOnly(cacheGroup *errgroup.Group, k8sVersion string) { + // If --download-only, complete the remaining downloads and exit. + if !viper.GetBool(downloadOnly) { + return + } + if err := doCacheBinaries(k8sVersion); err != nil { + exit.WithError("Failed to cache binaries", err) + } + waitCacheImages(cacheGroup) + if err := CacheImagesInConfigFile(); err != nil { + exit.WithError("Failed to cache images", err) + } + out.T(out.Check, "Download complete!") + os.Exit(0) + +} + +func startMachine(config *cfg.Config) (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) } - defer m.Close() - - // If --download-only, complete the remaining downloads and exit. - if viper.GetBool(downloadOnly) { - if err := doCacheBinaries(k8sVersion); err != nil { - exit.WithError("Failed to cache binaries", err) - } - waitCacheImages(&cacheGroup) - if err := CacheImagesInConfigFile(); err != nil { - exit.WithError("Failed to cache images", err) - } - console.OutStyle(console.Check, "Download complete!") - return - } - - host, preexisting := startHost(m, config.MachineConfig) + host, preExists = startHost(m, config.MachineConfig) ip := validateNetwork(host) - // Bypass proxy for minikube's vm ip + // Bypass proxy for minikube's vm host ip err = proxy.ExcludeIP(ip) if err != nil { - console.ErrT(console.FailureType, "Failed to set NO_PROXY Env. Please use `export NO_PROXY=$NO_PROXY,{{.ip}}`.", console.Arg{"ip": ip}) + 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 config.KubernetesConfig.NodeIP = ip if err := saveConfig(config); err != nil { exit.WithError("Failed to save config", err) } - runner, err := machine.CommandRunner(host) + runner, err = machine.CommandRunner(host) if err != nil { exit.WithError("Failed to get command runner", err) } - cr := configureRuntimes(runner) - showVersionInfo(k8sVersion, cr) + return runner, preExists, m, host +} - // prepareHostEnvironment uses the downloaded images, so we need to wait for background task completion. - waitCacheImages(&cacheGroup) - - bs := prepareHostEnvironment(m, config.KubernetesConfig) - - // The kube config must be update must come before bootstrapping, otherwise health checks may use a stale IP - kubeconfig := updateKubeConfig(host, &config) - bootstrapCluster(bs, cr, runner, config.KubernetesConfig, preexisting, isUpgrade) - configureMounts() - if err = LoadCachedImagesInConfigFile(); err != nil { - console.Failure("Unable to load cached images from config file.") +func getKubernetesVersion() (k8sVersion string, isUpgrade bool) { + oldConfig, err := cfg.Load() + if err != nil && !os.IsNotExist(err) { + exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err}) } - - if config.MachineConfig.VMDriver == constants.DriverNone { - console.OutStyle(console.StartingNone, "Configuring local host environment ...") - prepareNone() - } - - if err := bs.WaitCluster(config.KubernetesConfig); err != nil { - exit.WithError("Wait failed", err) - } - showKubectlConnectInfo(kubeconfig) - + return validateKubernetesVersions(oldConfig) } func downloadISO(config cfg.Config) { @@ -288,7 +383,7 @@ func downloadISO(config cfg.Config) { } } -func skipCache(config cfg.Config) { +func skipCache(config *cfg.Config) { if viper.GetString(vmDriver) == constants.DriverNone { viper.Set(cacheImages, false) config.KubernetesConfig.ShouldLoadCachedImages = false @@ -297,24 +392,24 @@ func skipCache(config cfg.Config) { func showVersionInfo(k8sVersion string, cr cruntime.Manager) { version, _ := cr.Version() - console.OutT(cr.Style(), "Configuring environment for Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}}", console.Arg{"k8sVersion": k8sVersion, "runtime": cr.Name(), "runtimeVersion": version}) + out.T(cr.Style(), "Preparing Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}} ...", out.V{"k8sVersion": k8sVersion, "runtime": cr.Name(), "runtimeVersion": version}) for _, v := range dockerOpt { - console.OutStyle(console.Option, "opt %s", v) + out.T(out.Option, "opt {{.docker_option}}", out.V{"docker_option": v}) } for _, v := range dockerEnv { - console.OutStyle(console.Option, "env %s", v) + out.T(out.Option, "env {{.docker_env}}", out.V{"docker_env": v}) } } func showKubectlConnectInfo(kubeconfig *pkgutil.KubeConfigSetup) { if kubeconfig.KeepContext { - console.OutT(console.Kubectl, "To connect to this cluster, use: kubectl --context={{.name}}", console.Arg{"name": kubeconfig.ClusterName}) + out.T(out.Kubectl, "To connect to this cluster, use: kubectl --context={{.name}}", out.V{"name": kubeconfig.ClusterName}) } else { - console.OutT(console.Ready, "Done! kubectl is now configured to use {{.name}}", console.Arg{"name": cfg.GetMachineName()}) + out.T(out.Ready, `Done! kubectl is now configured to use "{{.name}}"`, out.V{"name": cfg.GetMachineName()}) } _, err := exec.LookPath("kubectl") if err != nil { - console.OutStyle(console.Tip, "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/") + out.T(out.Tip, "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/") } } @@ -377,10 +472,9 @@ func validateUser() { // Check if minikube needs to run with sudo or not. if err == nil { if d == constants.DriverNone && u.Name != "root" { - exit.Usage("Please run with sudo. the vm-driver %q requires sudo.", constants.DriverNone) - + exit.UsageT(`Please run with sudo. the vm-driver "{{.driver_name}}" requires sudo.`, out.V{"driver_name": constants.DriverNone}) } else if u.Name == "root" && !(d == constants.DriverHyperv || d == constants.DriverNone) { - console.OutT(console.WarningType, "Please don't run minikube as root or with 'sudo' privileges. It isn't necessary with {{.driver}} driver.", console.Arg{"driver": d}) + out.T(out.WarningType, "Please don't run minikube as root or with 'sudo' privileges. It isn't necessary with {{.driver}} driver.", out.V{"driver": d}) } } else { @@ -393,7 +487,7 @@ func validateUser() { func validateConfig() { diskSizeMB := pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize)) if diskSizeMB < pkgutil.CalculateSizeInMB(constants.MinimumDiskSize) { - exit.WithCode(exit.Config, "Requested disk size (%dMB) is less than minimum of (%dMB)", diskSizeMB, pkgutil.CalculateSizeInMB(constants.MinimumDiskSize)) + exit.WithCodeT(exit.Config, "Requested disk size {{.size_in_mb}} is less than minimum of {{.size_in_mb2}}", out.V{"size_in_mb": diskSizeMB, "size_in_mb2": pkgutil.CalculateSizeInMB(constants.MinimumDiskSize)}) } err := autoSetOptions(viper.GetString(vmDriver)) @@ -403,17 +497,18 @@ func validateConfig() { memorySizeMB := pkgutil.CalculateSizeInMB(viper.GetString(memory)) if memorySizeMB < pkgutil.CalculateSizeInMB(constants.MinimumMemorySize) { - exit.Usage("Requested memory allocation (%dMB) is less than the minimum allowed of %dMB", memorySizeMB, pkgutil.CalculateSizeInMB(constants.MinimumMemorySize)) + exit.UsageT("Requested memory allocation {{.size_in_mb}} is less than the minimum allowed of {{.size_in_mb2}}", out.V{"size_in_mb": memorySizeMB, "size_in_mb2": pkgutil.CalculateSizeInMB(constants.MinimumMemorySize)}) } if memorySizeMB < pkgutil.CalculateSizeInMB(constants.DefaultMemorySize) { - console.OutT(console.Notice, "Requested memory allocation ({{.memory}}MB) is less than the default memory allocation of {{.default}}MB. Beware that minikube might not work correctly or crash unexpectedly.", console.Arg{"memory": memorySizeMB, "default": pkgutil.CalculateSizeInMB(constants.DefaultMemorySize)}) + out.T(out.Notice, "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.", + out.V{"memory": memorySizeMB, "default_memorysize": pkgutil.CalculateSizeInMB(constants.DefaultMemorySize)}) } // check that kubeadm extra args contain only whitelisted parameters for param := range extraOptions.AsMap().Get(kubeadm.Kubeadm) { if !pkgutil.ContainsString(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmCmdParam], param) && !pkgutil.ContainsString(kubeadm.KubeadmExtraArgsWhitelist[kubeadm.KubeadmConfigParam], param) { - exit.Usage("Sorry, the kubeadm.%s parameter is currently not supported by --extra-config", param) + exit.UsageT("Sorry, the kubeadm.{{.parameter_name}} parameter is currently not supported by --extra-config", out.V{"parameter_name": param}) } } @@ -431,7 +526,7 @@ func validateRegistryMirror() { glog.Errorln("Error Parsing URL: ", err) } if (URL.Scheme != "http" && URL.Scheme != "https") || URL.Path != "" { - exit.Usage("Sorry, url provided with --registry-mirror flag is invalid %q", loc) + exit.UsageT("Sorry, url provided with --registry-mirror flag is invalid {{.url}}", out.V{"url": loc}) } } @@ -505,9 +600,9 @@ func generateConfig(cmd *cobra.Command, k8sVersion string) (cfg.Config, error) { if !found { if autoSelectedRepository == "" { - exit.WithCode(exit.Failure, "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag") + exit.WithCodeT(exit.Failure, "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag") } else { - console.Warning("None of known repositories in your location is accessible. Use %s as fallback.", autoSelectedRepository) + out.WarningT("None of known repositories in your location is accessible. Use {{.image_repository_name}} as fallback.", out.V{"image_repository_name": autoSelectedRepository}) } } @@ -515,7 +610,7 @@ func generateConfig(cmd *cobra.Command, k8sVersion string) (cfg.Config, error) { } if repository != "" { - console.OutT(console.SuccessType, "Using image repository {{.name}}", console.Arg{"name": repository}) + out.T(out.SuccessType, "Using image repository {{.name}}", out.V{"name": repository}) } cfg := cfg.Config{ @@ -529,7 +624,6 @@ func generateConfig(cmd *cobra.Command, k8sVersion string) (cfg.Config, error) { ContainerRuntime: viper.GetString(containerRuntime), HyperkitVpnKitSock: viper.GetString(vpnkitSock), HyperkitVSockPorts: viper.GetStringSlice(vsockPorts), - XhyveDiskDriver: viper.GetString(xhyveDiskDriver), NFSShare: viper.GetStringSlice(nfsShare), NFSSharesRoot: viper.GetString(nfsSharesRoot), DockerEnv: dockerEnv, @@ -583,31 +677,35 @@ func autoSetOptions(vmDriver string) error { } // prepareNone prepares the user and host for the joy of the "none" driver -func prepareNone() { +func prepareNone(vmDriver string) { + if vmDriver != constants.DriverNone { + return + } + out.T(out.StartingNone, "Configuring local host environment ...") if viper.GetBool(cfg.WantNoneDriverWarning) { - console.OutLn("") - console.Warning("The 'none' driver provides limited isolation and may reduce system security and reliability.") - console.Warning("For more information, see:") - console.OutStyle(console.URL, "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md") - console.OutLn("") + out.T(out.Empty, "") + out.WarningT("The 'none' driver provides limited isolation and may reduce system security and reliability.") + out.WarningT("For more information, see:") + out.T(out.URL, "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md") + out.T(out.Empty, "") } if os.Getenv("CHANGE_MINIKUBE_NONE_USER") == "" { home := os.Getenv("HOME") - console.Warning("kubectl and minikube configuration will be stored in %s", home) - console.Warning("To use kubectl or minikube commands as your own user, you may") - console.Warning("need to relocate them. For example, to overwrite your own settings:") + out.WarningT("kubectl and minikube configuration will be stored in {{.home_folder}}", out.V{"home_folder": home}) + out.WarningT("To use kubectl or minikube commands as your own user, you may") + out.WarningT("need to relocate them. For example, to overwrite your own settings:") - console.OutLn("") - console.OutStyle(console.Command, "sudo mv %s/.kube %s/.minikube $HOME", home, home) - console.OutStyle(console.Command, "sudo chown -R $USER $HOME/.kube $HOME/.minikube") - console.OutLn("") + out.T(out.Empty, "") + out.T(out.Command, "sudo mv {{.home_folder}}/.kube {{.home_folder}}/.minikube $HOME", out.V{"home_folder": home}) + out.T(out.Command, "sudo chown -R $USER $HOME/.kube $HOME/.minikube") + out.T(out.Empty, "") - console.OutStyle(console.Tip, "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true") + out.T(out.Tip, "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true") } if err := pkgutil.MaybeChownDirRecursiveToMinikubeUser(constants.GetMinipath()); err != nil { - exit.WithCode(exit.Permissions, "Failed to chown %s: %v", constants.GetMinipath(), err) + exit.WithCodeT(exit.Permissions, "Failed to chown {{.minikube_dir_path}}: {{.error}}", out.V{"minikube_dir_path": constants.GetMinipath(), "error": err}) } } @@ -644,14 +742,14 @@ func validateNetwork(h *host.Host) string { for _, k := range proxy.EnvVars { if v := os.Getenv(k); v != "" { if !optSeen { - console.OutStyle(console.Internet, "Found network options:") + out.T(out.Internet, "Found network options:") optSeen = true } - console.OutStyle(console.Option, "%s=%s", k, v) + 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 { - console.Warning("You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (%s). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details", ip) + out.WarningT("You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP ({{.ip_address}}). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details", out.V{"ip_address": ip}) warnedOnce = true } } @@ -671,7 +769,7 @@ func validateKubernetesVersions(old *cfg.Config) (string, bool) { nvs, err := semver.Make(strings.TrimPrefix(rawVersion, version.VersionPrefix)) if err != nil { - exit.WithCode(exit.Data, "Unable to parse %q: %v", rawVersion, err) + exit.WithCodeT(exit.Data, `Unable to parse "{{.kubenretes_version}}": {{.error}}`, out.V{"kubenretes_version": rawVersion, "error": err}) } nv := version.VersionPrefix + nvs.String() @@ -686,24 +784,24 @@ func validateKubernetesVersions(old *cfg.Config) (string, bool) { if nvs.LT(ovs) { nv = version.VersionPrefix + ovs.String() - console.ErrT(console.Conflict, "Kubernetes downgrade is not supported, will continue to use {{.version}}", console.Arg{"version": nv}) + out.ErrT(out.Conflict, "Kubernetes downgrade is not supported, will continue to use {{.version}}", out.V{"version": nv}) return nv, isUpgrade } if nvs.GT(ovs) { - console.OutT(console.ThumbsUp, "minikube will upgrade the local cluster from Kubernetes {{.old}} to {{.new}}", console.Arg{"old": ovs, "new": nvs}) + out.T(out.ThumbsUp, "Upgrading from Kubernetes {{.old}} to {{.new}}", out.V{"old": ovs, "new": nvs}) isUpgrade = true } return nv, isUpgrade } -// prepareHostEnvironment adds any requested files into the VM before Kubernetes is started -func prepareHostEnvironment(api libmachine.API, kc cfg.KubernetesConfig) bootstrapper.Bootstrapper { - bs, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper)) +// setupKubeAdm adds any requested files into the VM before Kubernetes is started +func setupKubeAdm(mAPI libmachine.API, kc cfg.KubernetesConfig) bootstrapper.Bootstrapper { + bs, err := getClusterBootstrapper(mAPI, viper.GetString(cmdcfg.Bootstrapper)) if err != nil { exit.WithError("Failed to get bootstrapper", err) } for _, eo := range extraOptions { - console.OutStyle(console.Option, "%s.%s=%s", eo.Component, eo.Key, eo.Value) + out.T(out.Option, "{{.extra_option_component_name}}.{{.key}}={{.value}}", out.V{"extra_option_component_name": eo.Component, "key": eo.Key, "value": eo.Value}) } // Loads cached images, generates config files, download binaries if err := bs.UpdateCluster(kc); err != nil { @@ -748,7 +846,7 @@ func configureRuntimes(runner cruntime.CommandRunner) cruntime.Manager { config := cruntime.Config{Type: viper.GetString(containerRuntime), Runner: runner} cr, err := cruntime.New(config) if err != nil { - exit.WithError(fmt.Sprintf("Failed runtime for %+v", config), err) + exit.WithError("Failed runtime", err) } disableOthers := true @@ -769,21 +867,21 @@ func bootstrapCluster(bs bootstrapper.Bootstrapper, r cruntime.Manager, runner c bsName := viper.GetString(cmdcfg.Bootstrapper) if isUpgrade || !preexisting { - console.OutStyle(console.Pulling, "Pulling images ...") + out.T(out.Pulling, "Pulling images ...") if err := bs.PullImages(kc); err != nil { - console.OutT(console.FailureType, "Unable to pull images, which may be OK: {{.error}}", console.Arg{"error": err}) + out.T(out.FailureType, "Unable to pull images, which may be OK: {{.error}}", out.V{"error": err}) } } if preexisting { - console.OutT(console.Restarting, "Relaunching Kubernetes {{.version}} using {{.bootstrapper}} ... ", console.Arg{"version": kc.KubernetesVersion, "bootstrapper": bsName}) + out.T(out.Restarting, "Relaunching Kubernetes using {{.bootstrapper}} ... ", out.V{"bootstrapper": bsName}) if err := bs.RestartCluster(kc); err != nil { exit.WithLogEntries("Error restarting cluster", err, logs.FindProblems(r, bs, runner)) } return } - console.OutStyle(console.Launch, "Launching Kubernetes ... ") + out.T(out.Launch, "Launching Kubernetes ... ") if err := bs.StartCluster(kc); err != nil { exit.WithLogEntries("Error starting cluster", err, logs.FindProblems(r, bs, runner)) } @@ -795,7 +893,7 @@ func configureMounts() { return } - console.OutT(console.Mounting, "Creating mount {{.name}} ...", console.Arg{"name": viper.GetString(mountString)}) + out.T(out.Mounting, "Creating mount {{.name}} ...", out.V{"name": viper.GetString(mountString)}) path := os.Args[0] mountDebugVal := 0 if glog.V(8) { @@ -816,7 +914,7 @@ func configureMounts() { } // saveConfig saves profile cluster configuration in $MINIKUBE_HOME/profiles//config.json -func saveConfig(clusterConfig cfg.Config) error { +func saveConfig(clusterConfig *cfg.Config) error { data, err := json.MarshalIndent(clusterConfig, "", " ") if err != nil { return err @@ -860,39 +958,60 @@ func saveConfig(clusterConfig cfg.Config) error { } func validateDriverVersion(vmDriver string) { - if vmDriver == constants.DriverKvm2 { - cmd := exec.Command("docker-machine-driver-kvm2", "version") - output, err := cmd.Output() + var ( + driverExecutable string + driverDocumentation string + ) - // we don't want to fail if an error was returned, - // libmachine has a nice message for the user if the driver isn't present - if err != nil { - console.Warning("Error checking driver version: %v", err) - return - } + switch vmDriver { + case constants.DriverKvm2: + driverExecutable = fmt.Sprintf("docker-machine-driver-%s", constants.DriverKvm2) + driverDocumentation = fmt.Sprintf("%s#%s", constants.DriverDocumentation, "kvm2-upgrade") + case constants.DriverHyperkit: + driverExecutable = fmt.Sprintf("docker-machine-driver-%s", constants.DriverHyperkit) + driverDocumentation = fmt.Sprintf("%s#%s", constants.DriverDocumentation, "hyperkit-upgrade") + default: // driver doesn't support version + return + } - v := extractVMDriverVersion(string(output)) + cmd := exec.Command(driverExecutable, "version") + output, err := cmd.Output() - // if the driver doesn't have return any version, it is really old, we force a upgrade. - if len(v) == 0 { - exit.WithCode(exit.Failure, "Please upgrade the 'docker-machine-driver-kvm2'. %s", constants.KVMDocumentation) - } + // we don't want to fail if an error was returned, + // libmachine has a nice message for the user if the driver isn't present + if err != nil { + out.WarningT("Error checking driver version: {{.error}}", out.V{"error": err}) + return + } - vmDriverVersion, err := semver.Make(v) - if err != nil { - console.Warning("Error parsing vmDriver version: %v", err) - return - } + v := extractVMDriverVersion(string(output)) - minikubeVersion, err := version.GetSemverVersion() - if err != nil { - console.Warning("Error parsing minukube version: %v", err) - return - } + // if the driver doesn't have return any version, it is really old, we force a upgrade. + if len(v) == 0 { + exit.WithCodeT( + exit.Failure, + "Please upgrade the '{{.driver_executable}}'. {{.documentation_url}}", + out.V{"driver_executable": driverExecutable, "documentation_url": driverDocumentation}, + ) + } - if vmDriverVersion.LT(minikubeVersion) { - console.Warning("The 'docker-machine-driver-kvm2' version is old. Please consider upgrading. %s", constants.KVMDocumentation) - } + vmDriverVersion, err := semver.Make(v) + if err != nil { + out.WarningT("Error parsing vmDriver version: {{.error}}", out.V{"error": err}) + return + } + + minikubeVersion, err := version.GetSemverVersion() + if err != nil { + out.WarningT("Error parsing minukube version: {{.error}}", out.V{"error": err}) + return + } + + if vmDriverVersion.LT(minikubeVersion) { + out.WarningT( + "There's a new version for '{{.driver_executable}}'. Please consider upgrading. {{.documentation_url}}", + out.V{"driver_executable": driverExecutable, "documentation_url": driverDocumentation}, + ) } } diff --git a/cmd/minikube/cmd/status.go b/cmd/minikube/cmd/status.go index 668ee9815a..3cc00ce6c1 100644 --- a/cmd/minikube/cmd/status.go +++ b/cmd/minikube/cmd/status.go @@ -31,6 +31,7 @@ import ( "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" pkgutil "k8s.io/minikube/pkg/util" ) @@ -61,7 +62,7 @@ var statusCmd = &cobra.Command{ var returnCode = 0 api, err := machine.NewAPIClient() if err != nil { - exit.WithCode(exit.Unavailable, "Error getting client: %v", err) + exit.WithCodeT(exit.Unavailable, "Error getting client: {{.error}}", out.V{"error": err}) } defer api.Close() @@ -75,7 +76,7 @@ var statusCmd = &cobra.Command{ apiserverSt := state.None.String() if hostSt == state.Running.String() { - clusterBootstrapper, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper)) + clusterBootstrapper, err := getClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper)) if err != nil { exit.WithError("Error getting bootstrapper", err) } @@ -143,5 +144,4 @@ func init() { statusCmd.Flags().StringVar(&statusFormat, "format", constants.DefaultStatusFormat, `Go template format string for the status output. The format for Go templates can be found here: https://golang.org/pkg/text/template/ For the list accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status`) - RootCmd.AddCommand(statusCmd) } diff --git a/cmd/minikube/cmd/stop.go b/cmd/minikube/cmd/stop.go index 6d80a998d9..139d155d58 100644 --- a/cmd/minikube/cmd/stop.go +++ b/cmd/minikube/cmd/stop.go @@ -26,10 +26,10 @@ import ( cmdUtil "k8s.io/minikube/cmd/util" "k8s.io/minikube/pkg/minikube/cluster" pkg_config "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" pkgutil "k8s.io/minikube/pkg/util" ) @@ -52,27 +52,27 @@ func runStop(cmd *cobra.Command, args []string) { defer api.Close() nonexistent := false - stop := func() (err error) { err = cluster.StopHost(api) switch err := errors.Cause(err).(type) { case mcnerror.ErrHostDoesNotExist: - console.OutStyle(console.Meh, "%q VM does not exist, nothing to stop", profile) + out.T(out.Meh, `"{{.profile_name}}" VM does not exist, nothing to stop`, out.V{"profile_name": profile}) nonexistent = true return nil default: return err } } - if err := pkgutil.RetryAfter(5, stop, 2*time.Second); err != nil { + if err := pkgutil.RetryAfter(3, stop, 2*time.Second); err != nil { exit.WithError("Unable to stop VM", err) } + if !nonexistent { - console.OutStyle(console.Stopped, "%q stopped.", profile) + out.T(out.Stopped, `"{{.profile_name}}" stopped.`, out.V{"profile_name": profile}) } if err := cmdUtil.KillMountProcess(); err != nil { - console.OutStyle(console.WarningType, "Unable to kill mount process: %s", err) + out.T(out.WarningType, "Unable to kill mount process: {{.error}}", out.V{"error": err}) } machineName := pkg_config.GetMachineName() @@ -81,7 +81,3 @@ func runStop(cmd *cobra.Command, args []string) { exit.WithError("update config", err) } } - -func init() { - RootCmd.AddCommand(stopCmd) -} diff --git a/cmd/minikube/cmd/tunnel.go b/cmd/minikube/cmd/tunnel.go index f769da0870..dc5bdb7a46 100644 --- a/cmd/minikube/cmd/tunnel.go +++ b/cmd/minikube/cmd/tunnel.go @@ -86,5 +86,4 @@ var tunnelCmd = &cobra.Command{ func init() { tunnelCmd.Flags().BoolVarP(&cleanup, "cleanup", "c", false, "call with cleanup=true to remove old tunnels") - RootCmd.AddCommand(tunnelCmd) } diff --git a/cmd/minikube/cmd/update-check.go b/cmd/minikube/cmd/update-check.go index fe61530768..7fa4ebcbde 100644 --- a/cmd/minikube/cmd/update-check.go +++ b/cmd/minikube/cmd/update-check.go @@ -18,10 +18,10 @@ package cmd import ( "github.com/spf13/cobra" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/notify" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/version" ) @@ -41,14 +41,10 @@ var updateCheckCmd = &cobra.Command{ } if len(r) < 1 { - exit.WithCode(exit.Data, "Update server returned an empty list") + exit.WithCodeT(exit.Data, "Update server returned an empty list") } - console.OutLn("CurrentVersion: %s", version.GetVersion()) - console.OutLn("LatestVersion: %s", r[0].Name) + out.Ln("CurrentVersion: %s", version.GetVersion()) + out.Ln("LatestVersion: %s", r[0].Name) }, } - -func init() { - RootCmd.AddCommand(updateCheckCmd) -} diff --git a/cmd/minikube/cmd/update-context.go b/cmd/minikube/cmd/update-context.go index 41918bac70..94743d5c74 100644 --- a/cmd/minikube/cmd/update-context.go +++ b/cmd/minikube/cmd/update-context.go @@ -20,10 +20,10 @@ import ( "github.com/spf13/cobra" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/util" ) @@ -49,14 +49,10 @@ var updateContextCmd = &cobra.Command{ exit.WithError("update config", err) } if updated { - console.OutStyle(console.Celebrate, "%s IP has been updated to point at %s", machineName, ip) + out.T(out.Celebrate, "{{.machine}} IP has been updated to point at {{.ip}}", out.V{"machine": machineName, "ip": ip}) } else { - console.OutStyle(console.Meh, "%s IP was already correctly configured for %s", machineName, ip) + out.T(out.Meh, "{{.machine}} IP was already correctly configured for {{.ip}}", out.V{"machine": machineName, "ip": ip}) } }, } - -func init() { - RootCmd.AddCommand(updateContextCmd) -} diff --git a/cmd/minikube/cmd/version.go b/cmd/minikube/cmd/version.go index 073f95b879..a7cb944d0d 100644 --- a/cmd/minikube/cmd/version.go +++ b/cmd/minikube/cmd/version.go @@ -18,7 +18,7 @@ package cmd import ( "github.com/spf13/cobra" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/version" ) @@ -31,14 +31,10 @@ var versionCmd = &cobra.Command{ enableUpdateNotification = false }, Run: func(command *cobra.Command, args []string) { - console.OutLn("minikube version: %v", version.GetVersion()) + out.Ln("minikube version: %v", version.GetVersion()) gitCommitID := version.GetGitCommitID() if gitCommitID != "" { - console.OutLn("commit: %v", gitCommitID) + out.Ln("commit: %v", gitCommitID) } }, } - -func init() { - RootCmd.AddCommand(versionCmd) -} diff --git a/cmd/minikube/main.go b/cmd/minikube/main.go index fdc47903b5..fef04d79b5 100644 --- a/cmd/minikube/main.go +++ b/cmd/minikube/main.go @@ -23,12 +23,16 @@ import ( "os" "strconv" + // initflag must be imported before any other minikube pkg. + // Fix for https://github.com/kubernetes/minikube/issues/4866 + _ "k8s.io/minikube/pkg/initflag" + "github.com/golang/glog" "github.com/pkg/profile" "k8s.io/minikube/cmd/minikube/cmd" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/translate" _ "k8s.io/minikube/pkg/provision" ) @@ -45,8 +49,8 @@ func main() { if os.Getenv(constants.IsMinikubeChildProcess) == "" { machine.StartDriver() } - console.SetOutFile(os.Stdout) - console.SetErrFile(os.Stderr) + out.SetOutFile(os.Stdout) + out.SetErrFile(os.Stderr) translate.DetermineLocale() cmd.Execute() } diff --git a/deploy/addons/ingress/ingress-dp.yaml.tmpl b/deploy/addons/ingress/ingress-dp.yaml.tmpl index 16c2a93e3c..46806633ac 100644 --- a/deploy/addons/ingress/ingress-dp.yaml.tmpl +++ b/deploy/addons/ingress/ingress-dp.yaml.tmpl @@ -12,51 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: default-http-backend - namespace: kube-system - labels: - app.kubernetes.io/name: default-http-backend - app.kubernetes.io/part-of: kube-system - addonmanager.kubernetes.io/mode: Reconcile -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: default-http-backend - addonmanager.kubernetes.io/mode: Reconcile - template: - metadata: - labels: - app.kubernetes.io/name: default-http-backend - addonmanager.kubernetes.io/mode: Reconcile - spec: - terminationGracePeriodSeconds: 60 - containers: - - name: default-http-backend - # Any image is permissible as long as: - # 1. It serves a 404 page at / - # 2. It serves 200 on a /healthz endpoint - image: {{default "gcr.io/google_containers" .ImageRepository}}/defaultbackend{{.ExoticArch}}:1.4 - imagePullPolicy: IfNotPresent - livenessProbe: - httpGet: - path: /healthz - port: 8080 - scheme: HTTP - initialDelaySeconds: 30 - timeoutSeconds: 5 - ports: - - containerPort: 8080 - resources: - limits: - cpu: 20m - memory: 30Mi - requests: - cpu: 20m - memory: 30Mi --- apiVersion: extensions/v1beta1 kind: Deployment @@ -87,7 +42,7 @@ spec: serviceAccountName: nginx-ingress terminationGracePeriodSeconds: 60 containers: - - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller{{.ExoticArch}}:0.24.1 + - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller{{.ExoticArch}}:0.25.0 name: nginx-ingress-controller imagePullPolicy: IfNotPresent readinessProbe: @@ -121,7 +76,6 @@ spec: hostPort: 18080 args: - /nginx-ingress-controller - - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - --configmap=$(POD_NAMESPACE)/nginx-load-balancer-conf - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services diff --git a/deploy/addons/ingress/ingress-rbac.yaml.tmpl b/deploy/addons/ingress/ingress-rbac.yaml.tmpl index 082195ef35..a8c9bbf618 100644 --- a/deploy/addons/ingress/ingress-rbac.yaml.tmpl +++ b/deploy/addons/ingress/ingress-rbac.yaml.tmpl @@ -45,6 +45,7 @@ rules: - watch - apiGroups: - "extensions" + - "networking.k8s.io" resources: - ingresses verbs: @@ -60,6 +61,7 @@ rules: - patch - apiGroups: - "extensions" + - "networking.k8s.io" resources: - ingresses/status verbs: @@ -146,4 +148,4 @@ roleRef: subjects: - kind: ServiceAccount name: nginx-ingress - namespace: kube-system \ No newline at end of file + namespace: kube-system diff --git a/deploy/addons/ingress/ingress-svc.yaml.tmpl b/deploy/addons/ingress/ingress-svc.yaml.tmpl deleted file mode 100644 index f480bbfed4..0000000000 --- a/deploy/addons/ingress/ingress-svc.yaml.tmpl +++ /dev/null @@ -1,33 +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. - -apiVersion: v1 -kind: Service -metadata: - name: default-http-backend - namespace: kube-system - labels: - app.kubernetes.io/name: default-http-backend - app.kubernetes.io/part-of: kube-system - kubernetes.io/minikube-addons: ingress - kubernetes.io/minikube-addons-endpoint: ingress - addonmanager.kubernetes.io/mode: Reconcile -spec: - type: NodePort - ports: - - port: 80 - targetPort: 8080 - nodePort: 30001 - selector: - app.kubernetes.io/name: default-http-backend \ No newline at end of file diff --git a/deploy/addons/registry/registry-proxy.yaml.tmpl b/deploy/addons/registry/registry-proxy.yaml.tmpl index b5ab736e34..0a818fd9cb 100644 --- a/deploy/addons/registry/registry-proxy.yaml.tmpl +++ b/deploy/addons/registry/registry-proxy.yaml.tmpl @@ -10,6 +10,7 @@ spec: template: metadata: labels: + kubernetes.io/minikube-addons: registry addonmanager.kubernetes.io/mode: Reconcile spec: containers: diff --git a/deploy/addons/registry/registry-rc.yaml.tmpl b/deploy/addons/registry/registry-rc.yaml.tmpl index b39641aa47..7fe07e8392 100644 --- a/deploy/addons/registry/registry-rc.yaml.tmpl +++ b/deploy/addons/registry/registry-rc.yaml.tmpl @@ -13,6 +13,7 @@ spec: template: metadata: labels: + actual-registry: "true" kubernetes.io/minikube-addons: registry addonmanager.kubernetes.io/mode: Reconcile spec: diff --git a/deploy/addons/registry/registry-svc.yaml.tmpl b/deploy/addons/registry/registry-svc.yaml.tmpl index e9f618ae25..c48daefec0 100644 --- a/deploy/addons/registry/registry-svc.yaml.tmpl +++ b/deploy/addons/registry/registry-svc.yaml.tmpl @@ -12,4 +12,5 @@ spec: - port: 80 targetPort: 5000 selector: + actual-registry: "true" kubernetes.io/minikube-addons: registry diff --git a/deploy/iso/minikube-iso/package/crio-bin/conmon-config.h b/deploy/iso/minikube-iso/package/crio-bin/conmon-config.h new file mode 100755 index 0000000000..1783492d0d --- /dev/null +++ b/deploy/iso/minikube-iso/package/crio-bin/conmon-config.h @@ -0,0 +1,9 @@ + +#if !defined(CONFIG_H) +#define CONFIG_H + +#define BUF_SIZE 8192 +#define STDIO_BUF_SIZE 8192 +#define DEFAULT_SOCKET_PATH "/var/run/crio" + +#endif // CONFIG_H diff --git a/deploy/iso/minikube-iso/package/crio-bin/crio-bin.hash b/deploy/iso/minikube-iso/package/crio-bin/crio-bin.hash index dc0e1a46d4..2180406485 100644 --- a/deploy/iso/minikube-iso/package/crio-bin/crio-bin.hash +++ b/deploy/iso/minikube-iso/package/crio-bin/crio-bin.hash @@ -5,3 +5,4 @@ sha256 92588998dbb79002c38f65f84602b5659f0d0ef1cd36b1a568a2e40269b66816 v1.13.0. sha256 48e7cf64a757d62a3edf214e1b93b74d99f090ca924f956ede2494a260eab2db v1.13.1.tar.gz sha256 7435c4745017f06c260973b049440d924efe65b0df008d14175dfb8f5e23b599 v1.14.0.tar.gz sha256 1f6f72b1f89d4286b2d5b54a48f4d5ed4c0c01065d484635dcb343a706feb743 v1.14.1.tar.gz +sha256 f7041a92e2d3a4c341be8df58f1076ba57ecb5daa02b6c65e652530c5f242739 v1.15.0.tar.gz diff --git a/deploy/iso/minikube-iso/package/crio-bin/crio-bin.mk b/deploy/iso/minikube-iso/package/crio-bin/crio-bin.mk index 9331619cdf..8fbe0ae3be 100644 --- a/deploy/iso/minikube-iso/package/crio-bin/crio-bin.mk +++ b/deploy/iso/minikube-iso/package/crio-bin/crio-bin.mk @@ -4,9 +4,9 @@ # ################################################################################ -CRIO_BIN_VERSION = v1.14.1 -CRIO_BIN_COMMIT = b7644f67e6383cc862b3e37fb74fba334b0b2721 -CRIO_BIN_SITE = https://github.com/kubernetes-sigs/cri-o/archive +CRIO_BIN_VERSION = v1.15.0 +CRIO_BIN_COMMIT = 485227d727401fa0472a449b5df3b0537e314ebb +CRIO_BIN_SITE = https://github.com/cri-o/cri-o/archive CRIO_BIN_SOURCE = $(CRIO_BIN_VERSION).tar.gz CRIO_BIN_DEPENDENCIES = host-go libgpgme CRIO_BIN_GOPATH = $(@D)/_output @@ -23,8 +23,10 @@ define CRIO_BIN_USERS endef define CRIO_BIN_CONFIGURE_CMDS - mkdir -p $(CRIO_BIN_GOPATH)/src/github.com/kubernetes-sigs - ln -sf $(@D) $(CRIO_BIN_GOPATH)/src/github.com/kubernetes-sigs/cri-o + mkdir -p $(CRIO_BIN_GOPATH)/src/github.com/cri-o + ln -sf $(@D) $(CRIO_BIN_GOPATH)/src/github.com/cri-o/cri-o + # Generate conmon/config.h with a simplified bin/crio-config + $(CRIO_BIN_ENV) $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D) BUILDTAGS="containers_image_ostree_stub exclude_graphdriver_btrfs exclude_graphdriver_devicemapper containers_image_openpgp" conmon/config.h endef define CRIO_BIN_BUILD_CMDS @@ -45,9 +47,6 @@ define CRIO_BIN_INSTALL_TARGET_CMDS $(INSTALL) -Dm755 \ $(@D)/bin/pause \ $(TARGET_DIR)/usr/libexec/crio/pause - $(INSTALL) -Dm644 \ - $(@D)/seccomp.json \ - $(TARGET_DIR)/etc/crio/seccomp.json $(INSTALL) -Dm644 \ $(BR2_EXTERNAL_MINIKUBE_PATH)/package/crio-bin/crio.conf \ $(TARGET_DIR)/etc/crio/crio.conf diff --git a/deploy/iso/minikube-iso/package/crio-bin/crio-bin.patch b/deploy/iso/minikube-iso/package/crio-bin/crio-bin.patch new file mode 100644 index 0000000000..e66dd99275 --- /dev/null +++ b/deploy/iso/minikube-iso/package/crio-bin/crio-bin.patch @@ -0,0 +1,39 @@ +diff --git a/Makefile b/Makefile +index de79f63..a9ea13b 100644 +--- a/Makefile ++++ b/Makefile +@@ -136,7 +136,7 @@ crio.conf: bin/crio + release-note: ${RELEASE_TOOL} + ${RELEASE_TOOL} -n $(release) + +-conmon/config.h: git-vars cmd/crio-config/config.go oci/oci.go ++conmon/config.h: cmd/crio-config/config.go oci/oci.go + $(GO) build $(LDFLAGS) -tags "$(BUILDTAGS)" -o bin/crio-config $(PROJECT)/cmd/crio-config + ( cd conmon && $(CURDIR)/bin/crio-config ) + +diff --git a/cmd/crio/main.go b/cmd/crio/main.go +index 0bc347a..ab9969f 100644 +--- a/cmd/crio/main.go ++++ b/cmd/crio/main.go +@@ -207,7 +207,7 @@ func mergeConfig(config *server.Config, ctx *cli.Context) (string, error) { + } + + func writeCrioGoroutineStacks() { +- path := filepath.Join("/tmp", fmt.Sprintf("crio-goroutine-stacks-%s.log", strings.ReplaceAll(time.Now().Format(time.RFC3339), ":", ""))) ++ path := filepath.Join("/tmp", fmt.Sprintf("crio-goroutine-stacks-%s.log", strings.Replace(time.Now().Format(time.RFC3339), ":", "", -1))) + if err := utils.WriteGoroutineStacksToFile(path); err != nil { + logrus.Warnf("Failed to write goroutine stacks: %s", err) + } +diff --git a/oci/runtime_vm.go b/oci/runtime_vm.go +index 57a1fde..64f853f 100644 +--- a/oci/runtime_vm.go ++++ b/oci/runtime_vm.go +@@ -172,7 +172,7 @@ func (r *runtimeVM) startRuntimeDaemon(c *Container) error { + args = append(args, "start") + + // Modify the runtime path so that it complies with v2 shim API +- newRuntimePath := strings.ReplaceAll(r.path, "-", ".") ++ newRuntimePath := strings.Replace(r.path, "-", ".", -1) + + // Setup default namespace + r.ctx = namespaces.WithNamespace(r.ctx, namespaces.Default) diff --git a/deploy/iso/minikube-iso/package/crio-bin/crio.conf b/deploy/iso/minikube-iso/package/crio-bin/crio.conf index f096f44929..2d96ded019 100644 --- a/deploy/iso/minikube-iso/package/crio-bin/crio.conf +++ b/deploy/iso/minikube-iso/package/crio-bin/crio.conf @@ -5,6 +5,11 @@ # # Please refer to crio.conf(5) for details of all configuration options. +# CRI-O supports partial configuration reload during runtime, which can be +# done by sending SIGHUP to the running process. Currently supported options +# are explicitly mentioned with: 'This option supports live configuration +# reload'. + # CRI-O reads its storage defaults from the containers-storage.conf(5) file # located at /etc/containers/storage.conf. Modify this storage configuration if # you want to change the system's defaults. If you want to modify storage just @@ -28,9 +33,11 @@ storage_driver = "overlay" #] # If set to false, in-memory locking will be used instead of file-based locking. -file_locking = true +# **Deprecated** this option will be removed in the future. +file_locking = false # Path to the lock file. +# **Deprecated** this option will be removed in the future. file_locking_path = "/run/crio.lock" @@ -90,6 +97,9 @@ no_pivot = true # Path to the conmon binary, used for monitoring the OCI runtime. conmon = "/usr/libexec/crio/conmon" +# Cgroup setting for conmon +conmon_cgroup = "pod" + # Environment variable list for the conmon process, used for passing necessary # environment variables to conmon or the runtime. conmon_env = [ @@ -100,8 +110,9 @@ conmon_env = [ selinux = false # Path to the seccomp.json profile which is used as the default seccomp profile -# for the runtime. -seccomp_profile = "/etc/crio/seccomp.json" +# for the runtime. If not specified, then the internal default seccomp profile +# will be used. +seccomp_profile = "" # Used to change the name of the default AppArmor profile of CRI-O. The default # profile name is "crio-default-" followed by the version string of CRI-O. @@ -185,9 +196,13 @@ container_attach_socket_dir = "/var/run/crio" read_only = false # Changes the verbosity of the logs based on the level it is set to. Options -# are fatal, panic, error, warn, info, and debug. +# are fatal, panic, error, warn, info, and debug. This option supports live +# configuration reload. log_level = "error" +# The default log directory where all logs will go unless directly specified by the kubelet +log_dir = "/var/log/crio/pods" + # The UID mappings for the user namespace of each container. A range is # specified in the form containerUID:HostUID:Size. Multiple ranges must be # separated by comma. @@ -202,15 +217,19 @@ gid_mappings = "" # regarding the proper termination of the container. ctr_stop_timeout = 0 - # The "crio.runtime.runtimes" table defines a list of OCI compatible runtimes. - # The runtime to use is picked based on the runtime_handler provided by the CRI. - # If no runtime_handler is provided, the runtime will be picked based on the level - # of trust of the workload. - - [crio.runtime.runtimes.runc] - runtime_path = "/usr/bin/runc" - runtime_type = "oci" - +# ManageNetworkNSLifecycle determines whether we pin and remove network namespace +# and manage its lifecycle. +manage_network_ns_lifecycle = false + +# The "crio.runtime.runtimes" table defines a list of OCI compatible runtimes. +# The runtime to use is picked based on the runtime_handler provided by the CRI. +# If no runtime_handler is provided, the runtime will be picked based on the level +# of trust of the workload. + +[crio.runtime.runtimes.runc] +runtime_path = "/usr/bin/runc" +runtime_type = "oci" +runtime_root = "/run/runc" # The crio.image table contains settings pertaining to the management of OCI images. @@ -225,14 +244,21 @@ ctr_stop_timeout = 0 # Default transport for pulling images from a remote container storage. default_transport = "docker://" +# The path to a file containing credentials necessary for pulling images from +# secure registries. The file is similar to that of /var/lib/kubelet/config.json +global_auth_file = "" + # The image used to instantiate infra containers. +# This option supports live configuration reload. pause_image = "k8s.gcr.io/pause:3.1" -# If not empty, the path to a docker/config.json-like file containing credentials -# necessary for pulling the image specified by pause_image above. +# The path to a file containing credentials specific for pulling the pause_image from +# above. The file is similar to that of /var/lib/kubelet/config.json +# This option supports live configuration reload. pause_image_auth_file = "" # The command to run to have a container stay in the paused state. +# This option supports live configuration reload. pause_command = "/pause" # Path to the file which decides what sort of policy we use when deciding @@ -264,6 +290,6 @@ registries = [ network_dir = "/etc/cni/net.d/" # Paths to directories where CNI plugin binaries are located. -plugin_dir = [ +plugin_dirs = [ "/opt/cni/bin/", ] diff --git a/deploy/iso/minikube-iso/package/crio-bin/crio.conf.default b/deploy/iso/minikube-iso/package/crio-bin/crio.conf.default index 725a0e413e..86cb3df9ff 100644 --- a/deploy/iso/minikube-iso/package/crio-bin/crio.conf.default +++ b/deploy/iso/minikube-iso/package/crio-bin/crio.conf.default @@ -5,6 +5,11 @@ # # Please refer to crio.conf(5) for details of all configuration options. +# CRI-O supports partial configuration reload during runtime, which can be +# done by sending SIGHUP to the running process. Currently supported options +# are explicitly mentioned with: 'This option supports live configuration +# reload'. + # CRI-O reads its storage defaults from the containers-storage.conf(5) file # located at /etc/containers/storage.conf. Modify this storage configuration if # you want to change the system's defaults. If you want to modify storage just @@ -20,7 +25,7 @@ # Storage driver used to manage the storage of images and containers. Please # refer to containers-storage.conf(5) to see all available storage drivers. -#storage_driver = "overlay" +#storage_driver = "" # List to pass options to the storage driver. Please refer to # containers-storage.conf(5) to see all available storage options. @@ -28,9 +33,11 @@ #] # If set to false, in-memory locking will be used instead of file-based locking. -file_locking = true +# **Deprecated** this option will be removed in the future. +file_locking = false # Path to the lock file. +# **Deprecated** this option will be removed in the future. file_locking_path = "/run/crio.lock" @@ -90,6 +97,9 @@ no_pivot = false # Path to the conmon binary, used for monitoring the OCI runtime. conmon = "/usr/local/libexec/crio/conmon" +# Cgroup setting for conmon +conmon_cgroup = "pod" + # Environment variable list for the conmon process, used for passing necessary # environment variables to conmon or the runtime. conmon_env = [ @@ -100,8 +110,9 @@ conmon_env = [ selinux = false # Path to the seccomp.json profile which is used as the default seccomp profile -# for the runtime. -seccomp_profile = "/etc/crio/seccomp.json" +# for the runtime. If not specified, then the internal default seccomp profile +# will be used. +seccomp_profile = "" # Used to change the name of the default AppArmor profile of CRI-O. The default # profile name is "crio-default-" followed by the version string of CRI-O. @@ -185,9 +196,13 @@ container_attach_socket_dir = "/var/run/crio" read_only = false # Changes the verbosity of the logs based on the level it is set to. Options -# are fatal, panic, error, warn, info, and debug. +# are fatal, panic, error, warn, info, and debug. This option supports live +# configuration reload. log_level = "error" +# The default log directory where all logs will go unless directly specified by the kubelet +log_dir = "/var/log/crio/pods" + # The UID mappings for the user namespace of each container. A range is # specified in the form containerUID:HostUID:Size. Multiple ranges must be # separated by comma. @@ -202,15 +217,19 @@ gid_mappings = "" # regarding the proper termination of the container. ctr_stop_timeout = 0 - # The "crio.runtime.runtimes" table defines a list of OCI compatible runtimes. - # The runtime to use is picked based on the runtime_handler provided by the CRI. - # If no runtime_handler is provided, the runtime will be picked based on the level - # of trust of the workload. - - [crio.runtime.runtimes.runc] - runtime_path = "/usr/bin/runc" - runtime_type = "oci" - +# ManageNetworkNSLifecycle determines whether we pin and remove network namespace +# and manage its lifecycle. +manage_network_ns_lifecycle = false + +# The "crio.runtime.runtimes" table defines a list of OCI compatible runtimes. +# The runtime to use is picked based on the runtime_handler provided by the CRI. +# If no runtime_handler is provided, the runtime will be picked based on the level +# of trust of the workload. + +[crio.runtime.runtimes.runc] +runtime_path = "" +runtime_type = "oci" +runtime_root = "/run/runc" # The crio.image table contains settings pertaining to the management of OCI images. @@ -225,14 +244,21 @@ ctr_stop_timeout = 0 # Default transport for pulling images from a remote container storage. default_transport = "docker://" +# The path to a file containing credentials necessary for pulling images from +# secure registries. The file is similar to that of /var/lib/kubelet/config.json +global_auth_file = "" + # The image used to instantiate infra containers. +# This option supports live configuration reload. pause_image = "k8s.gcr.io/pause:3.1" -# If not empty, the path to a docker/config.json-like file containing credentials -# necessary for pulling the image specified by pause_image above. +# The path to a file containing credentials specific for pulling the pause_image from +# above. The file is similar to that of /var/lib/kubelet/config.json +# This option supports live configuration reload. pause_image_auth_file = "" # The command to run to have a container stay in the paused state. +# This option supports live configuration reload. pause_command = "/pause" # Path to the file which decides what sort of policy we use when deciding @@ -263,6 +289,6 @@ image_volumes = "mkdir" network_dir = "/etc/cni/net.d/" # Paths to directories where CNI plugin binaries are located. -plugin_dir = [ +plugin_dirs = [ "/opt/cni/bin/", ] diff --git a/deploy/iso/minikube-iso/package/docker-bin/docker-bin.hash b/deploy/iso/minikube-iso/package/docker-bin/docker-bin.hash index d57b3eee38..e5a4073aeb 100644 --- a/deploy/iso/minikube-iso/package/docker-bin/docker-bin.hash +++ b/deploy/iso/minikube-iso/package/docker-bin/docker-bin.hash @@ -11,3 +11,4 @@ sha256 346f9394393ee8db5f8bd1e229ee9d90e5b36931bdd754308b2ae68884dd6822 docker- sha256 99ca9395e9c7ffbf75537de71aa828761f492491d02bc6e29db2920fa582c6c5 docker-18.09.5.tgz sha256 1f3f6774117765279fce64ee7f76abbb5f260264548cf80631d68fb2d795bb09 docker-18.09.6.tgz sha256 e106ccfa2b1f60794faaa6bae57a2dac9dc4cb33e5541fad6a826ea525d01cc4 docker-18.09.7.tgz +sha256 12277eff64363f51ba2f20dd258bdc2c3248022996c0251921193ec6fd179e52 docker-18.09.8.tgz 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 03d938ef74..5f4b7dbde1 100644 --- a/deploy/iso/minikube-iso/package/docker-bin/docker-bin.mk +++ b/deploy/iso/minikube-iso/package/docker-bin/docker-bin.mk @@ -4,7 +4,7 @@ # ################################################################################ -DOCKER_BIN_VERSION = 18.09.7 +DOCKER_BIN_VERSION = 18.09.8 DOCKER_BIN_SITE = https://download.docker.com/linux/static/stable/x86_64 DOCKER_BIN_SOURCE = docker-$(DOCKER_BIN_VERSION).tgz diff --git a/docs/cli_commands.md b/docs/cli_commands.md index e10db275fd..34078095dd 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -247,7 +247,7 @@ minikube service [command] --- ### start -**Description -** Starts a local kubernetes cluster using VM. This command assumes you have already installed one of the VM drivers: **virtualbox/parallels/vmwarefusion/kvm/xhyve/hyperv**. +**Description -** Starts a local kubernetes cluster. **Usage -** `minikube start [flags]` **Available Flags -** ``` @@ -259,7 +259,7 @@ minikube service [command] --container-runtime string The container runtime to be used (docker, crio, containerd) (default "docker") --cpus int Number of CPUs allocated to the minikube VM (default 2) --cri-socket string The cri socket path to be used - --disable-driver-mounts Disables the filesystem mounts provided by the hypervisors (vboxfs, xhyve-9p) + --disable-driver-mounts Disables the filesystem mounts provided by the hypervisors (vboxfs) --disk-size string Disk size allocated to the minikube VM (format: [], where unit = b, k, m or g) (default "20000mb") --dns-domain string The cluster dns domain name used in the kubernetes cluster (default "cluster.local") --docker-env stringArray Environment variables to pass to the Docker daemon. (format: key=value) @@ -295,8 +295,7 @@ minikube service [command] --registry-mirror strings Registry mirrors to pass to the Docker daemon --service-cluster-ip-range string The CIDR to be used for service cluster IPs. (default "10.96.0.0/12") --uuid string Provide VM UUID to restore MAC address (only supported with Hyperkit driver). - --vm-driver string VM driver is one of: [virtualbox parallels vmwarefusion kvm xhyve hyperv hyperkit kvm2 vmware none] (default "virtualbox") - --xhyve-disk-driver string The disk driver to use [ahci-hd|virtio-blk] (only supported with xhyve driver) (default "ahci-hd") + --vm-driver string VM driver is one of: [virtualbox parallels vmwarefusion kvm hyperv hyperkit kvm2 vmware none] (default "virtualbox") ``` --- diff --git a/docs/contributors/principles.md b/docs/contributors/principles.md index f740678d6b..a2fa60022a 100644 --- a/docs/contributors/principles.md +++ b/docs/contributors/principles.md @@ -22,4 +22,4 @@ Here are some specific minikube features that align with our goal: ## Non-Goals * Simplifying Kubernetes production deployment experience -* Supporting all possible deployment configurations of Kubernetes like various types of storage, networking, etc. +* Supporting all possible deployment configurations of Kubernetes, such as storage, networking, etc. diff --git a/docs/drivers.md b/docs/drivers.md index 40ade7d5fd..f3f4814fa2 100644 --- a/docs/drivers.md +++ b/docs/drivers.md @@ -11,7 +11,7 @@ the host PATH: * [KVM2](#kvm2-driver) * [Hyperkit](#hyperkit-driver) -* [HyperV](#hyperv-driver) +* [Hyper-V](#hyper-v-driver) * [VMware](#vmware-unified-driver) * [Parallels](#parallels-driver) @@ -23,7 +23,7 @@ To install the KVM2 driver, first install and configure the prerequisites, namel * Debian or Ubuntu 18.x: `sudo apt install libvirt-clients libvirt-daemon-system qemu-kvm` * Ubuntu 16.x or older: `sudo apt install libvirt-bin libvirt-daemon-system qemu-kvm` -* Fedora/CentOS/RHEL: `sudo yum install libvirt-daemon-kvm qemu-kvm` +* Fedora/CentOS/RHEL: `sudo yum install libvirt libvirt-daemon-kvm qemu-kvm` * openSUSE/SLES: `sudo zypper install libvirt qemu-kvm` Check your installed virsh version: @@ -143,6 +143,13 @@ or, to use hyperkit as a default driver for minikube: minikube config set vm-driver hyperkit ``` +### Hyperkit upgrade + +```shell +curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit \ +&& sudo install -o root -g wheel -m 4755 docker-machine-driver-hyperkit /usr/local/bin/ +``` + ### Hyperkit troubleshoot Make sure you are running the lastest version of your driver. @@ -151,11 +158,11 @@ Make sure you are running the lastest version of your driver. docker-machine-driver-hyperkit version ``` -## HyperV driver +## Hyper-V driver -Hyper-v users may need to create a new external network switch as described [here](https://docs.docker.com/machine/drivers/hyper-v/). This step may prevent a problem in which `minikube start` hangs indefinitely, unable to ssh into the minikube virtual machine. In this add, add the `--hyperv-virtual-switch=switch-name` argument to the `minikube start` command. +Hyper-V users will need to create a new external network switch as described [here](https://docs.docker.com/machine/drivers/hyper-v/). This step may prevent a problem in which `minikube start` hangs indefinitely, unable to ssh into the minikube virtual machine. In this add, add the `--hyperv-virtual-switch=switch-name` argument to the `minikube start` command. -On some machines, having **dynamic memory management** turned on for the minikube VM can cause problems of unexpected and random restarts which manifests itself in simply losing the connection to the cluster, after which `minikube status` would simply state `stopped`. Machine restarts are caused due to following Hyper-V error: `The dynamic memory balancer could not add memory to the virtual machine 'minikube' because its configured maximum has been reached`. **Solution**: turned the dynamic memory management in hyper-v settings off (and allocate a fixed amount of memory to the machine). +Older Hyper-V VM's may have **dynamic memory management** enabled, which can cause problems of unexpected and random restarts which manifests itself in simply losing the connection to the cluster, after which `minikube status` would simply state `stopped`. **Solution**: run `minikube delete` to delete the old VM. To use the driver: diff --git a/docs/tunnel.md b/docs/tunnel.md index ba83e7bf82..8e41bf9dbe 100644 --- a/docs/tunnel.md +++ b/docs/tunnel.md @@ -10,7 +10,7 @@ If all cluster IP addresses and Load Balancers were made available on the miniku Tools like telepresence.io, sshuttle, and the OpenVPN chart provide similar capabilities already. -Also, Steve Sloka has provided a very detailed guide on how to setup a similar configuration [manually](https://stevesloka.com/2017/06/12/access-minikube-service-from-linux-host/). +Also, Steve Sloka has provided a very detailed guide on how to setup a similar configuration [manually](https://stevesloka.com/access-minikube-service-from-linux-host/). Elson Rodriguez has provided a similar guide, including a Minikube [external LB controller](https://github.com/elsonrodriguez/minikube-lb-patch). diff --git a/go.mod b/go.mod index fe64ef5064..2c3412bb74 100644 --- a/go.mod +++ b/go.mod @@ -3,109 +3,96 @@ module k8s.io/minikube go 1.12 require ( - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/Microsoft/go-winio v0.4.13 // indirect github.com/Parallels/docker-machine-parallels v1.3.0 github.com/Sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 // indirect + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/blang/semver v3.5.0+incompatible github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 // indirect + github.com/cenkalti/backoff v2.2.1+incompatible github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect - github.com/cpuguy83/go-md2man v1.0.4 // indirect - github.com/docker/distribution v2.7.1+incompatible // indirect - github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197 // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69 - github.com/docker/machine v0.16.1 + github.com/docker/docker v1.13.1 // indirect + github.com/docker/go-units v0.3.3 + github.com/docker/machine v0.16.1-0.20190718054102-a555e4f7a8f5 github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect - github.com/fatih/color v1.7.0 // indirect - github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 // indirect - github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e // indirect + github.com/go-ole/go-ole v1.2.4 // indirect github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 - github.com/golang/glog v0.0.0-20141105023935-44145f04b68c - github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 // indirect - github.com/google/btree v1.0.0 // indirect - github.com/google/go-cmp v0.2.0 - github.com/google/go-containerregistry v0.0.0-20190729175742-ef12d49c8daf + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + github.com/google/go-cmp v0.3.0 + github.com/google/go-containerregistry v0.0.0-20190318164241-019cdfc6adf9 github.com/google/go-github/v25 v25.0.2 - github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 // indirect - github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d // indirect github.com/gorilla/mux v1.7.1 // indirect - github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce // indirect + github.com/hashicorp/go-getter v1.3.0 github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 // indirect github.com/hashicorp/go-retryablehttp v0.5.4 - github.com/hashicorp/go-version v1.1.0 // indirect - github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 // indirect - github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1 // indirect github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8 - github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // 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/json-iterator/go v1.1.5 // indirect - github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 // indirect - github.com/kr/pretty v0.1.0 // indirect github.com/libvirt/libvirt-go v3.4.0+incompatible github.com/machine-drivers/docker-machine-driver-vmware v0.1.1 - github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4 // indirect github.com/mattn/go-colorable v0.1.1 // indirect github.com/mattn/go-isatty v0.0.5 - github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b // indirect github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 - github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49 // indirect github.com/moby/hyperkit v0.0.0-20171020124204-a12cd7250bcd - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd - github.com/onsi/ginkgo v1.8.0 // indirect - github.com/onsi/gomega v1.5.0 // indirect - github.com/opencontainers/go-digest v1.0.0-rc1 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect - github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca - github.com/pelletier/go-buffruneio v0.1.0 // indirect - github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pborman/uuid v1.2.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/browser v0.0.0-20160118053552-9302be274faa github.com/pkg/errors v0.8.1 github.com/pkg/profile v0.0.0-20161223203901-3a8809bd8a80 - github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6 // indirect github.com/pmezard/go-difflib v1.0.0 - github.com/r2d4/external-storage v0.0.0-20171222174501-8c0e8605dc7b - github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5 // indirect github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 // indirect - github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db // indirect - github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97 // indirect - github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a // indirect - github.com/spf13/cobra v0.0.0-20180228053838-6644d46b81fa - github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80 // indirect - github.com/spf13/pflag v1.0.1 - github.com/spf13/viper v1.0.0 - github.com/stretchr/testify v1.3.0 // indirect + github.com/shirou/gopsutil v2.18.12+incompatible + github.com/sirupsen/logrus v1.4.1 // indirect + github.com/spf13/cobra v0.0.5 + github.com/spf13/pflag v1.0.3 + github.com/spf13/viper v1.3.2 github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c // indirect github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 - golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 - golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c + golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a golang.org/x/sync v0.0.0-20190423024810-112230192c58 - golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b + golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f golang.org/x/text v0.3.2 - golang.org/x/time v0.0.0-20161028155119-f51c12702a4d // indirect gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/cheggaaa/pb.v1 v1.0.6 // indirect gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect - gopkg.in/inf.v0 v0.9.0 // indirect - gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect - k8s.io/api v0.0.0-20180712090710-2d6f90ab1293 - k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d - k8s.io/apiserver v0.0.0-20180914001516-67c892841170 // indirect - k8s.io/client-go v0.0.0-20180806134042-1f13a808da65 - k8s.io/kube-openapi v0.0.0-20180216212618-50ae88d24ede // indirect - k8s.io/kubernetes v1.11.3 + k8s.io/api v0.0.0 + k8s.io/apimachinery v0.0.0 + k8s.io/client-go v0.0.0 + k8s.io/kubectl v0.0.0-00010101000000-000000000000 + k8s.io/kubernetes v1.15.0 + sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.0+incompatible +) + +replace ( + k8s.io/api => k8s.io/kubernetes/staging/src/k8s.io/api v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/apiextensions-apiserver => k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/apimachinery => k8s.io/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/apiserver => k8s.io/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/cli-runtime => k8s.io/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/client-go => k8s.io/kubernetes/staging/src/k8s.io/client-go v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/cloud-provider => k8s.io/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/cluster-bootstrap => k8s.io/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/code-generator => k8s.io/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/component-base => k8s.io/kubernetes/staging/src/k8s.io/component-base v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/cri-api => k8s.io/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/csi-translation-lib => k8s.io/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/kube-aggregator => k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/kube-controller-manager => k8s.io/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/kube-proxy => k8s.io/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/kube-scheduler => k8s.io/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/kubectl => k8s.io/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/kubelet => k8s.io/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/legacy-cloud-providers => k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/metrics => k8s.io/kubernetes/staging/src/k8s.io/metrics v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/node-api => k8s.io/kubernetes/staging/src/k8s.io/node-api v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/sample-apiserver => k8s.io/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/sample-cli-plugin => k8s.io/kubernetes/staging/src/k8s.io/sample-cli-plugin v0.0.0-20190623232353-8c3b7d7679cc + k8s.io/sample-controller => k8s.io/kubernetes/staging/src/k8s.io/sample-controller v0.0.0-20190623232353-8c3b7d7679cc ) diff --git a/go.sum b/go.sum index beb960a809..81ccc950bc 100644 --- a/go.sum +++ b/go.sum @@ -1,160 +1,363 @@ +bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.36.0 h1:+aCSj7tOo2LODWVEuZDZeGCckdt6MlSF+X/rB3wUiS8= +cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/Azure/azure-sdk-for-go v21.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Microsoft/go-winio v0.4.13 h1:Hmi80lzZuI/CaYmlJp/b+FjZdRZhKu9c2mDVqKlLWVs= -github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20181220005116-f8e995905100/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Parallels/docker-machine-parallels v1.3.0 h1:RG1fyf3v1GwXMCeHRiZkB4tL9phFZEv6ixcvRZ1raN8= github.com/Parallels/docker-machine-parallels v1.3.0/go.mod h1:HCOMm3Hulq/xuEVQMyZOuQlA+dSZpFY5kdCTZWjMVis= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg= github.com/Sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 h1:k1A7eIeUk6rnX2yuagwljW/pDezkK8oSpvPumT9zdZY= github.com/Sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= +github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= +github.com/aws/aws-sdk-go v1.16.26 h1:GWkl3rkRO/JGRTWoLLIqwf7AWC4/W/1hMOUZqmX0js4= +github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e/go.mod h1:uHBSeeATKpVazAACZBDPL/Nk/UhQDDsJWDlqYJo8/Us= +github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 h1:+ziP/wVJWuAORkjv7386TRidVKY57X0bXBZFMeFlW+U= github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9/go.mod h1:txokOny9wavBtq2PWuHmj1P+eFwpCsj+gQeNNANChfU= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/client9/misspell v0.0.0-20170928000206-9ce5d979ffda/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cfssl v0.0.0-20180726162950-56268a613adf/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:Yg2hDs4b13Evkpj42FU2idX2cVXVFqQSheXYKM86Qsk= github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:MgJyK38wkzZbiZSKeIeFankxxSA8gayko/nr5x5bgBA= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= -github.com/cpuguy83/go-md2man v1.0.4 h1:OwjhDpK9YGCcI5CDf8HcdfsXqr6znFyAJfuZ27ixJsc= +github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= +github.com/codedellemc/goscaleio v0.0.0-20170830184815-20e2ce2cf885/go.mod h1:JIHmDHNZO4tmA3y3RHp6+Gap6kFsNf55W9Pn/3YS9IY= +github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= +github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= +github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containernetworking/cni v0.6.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/rkt v1.30.0/go.mod h1:O634mlH6U7qk87poQifK6M2rsFNt+FyUTWNMnP1hF1U= github.com/cpuguy83/go-md2man v1.0.4/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cyphar/filepath-securejoin v0.0.0-20170720062807-ae69057f2299/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v0.0.0-20170829104524-6e570ed0a266/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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 v0.0.0-20180531152204-71cd53e4a197 h1:raQhUHOMIAZAWHmo3hLEwoIy0aVkKb2uxZdWw/Up+HI= -github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20170726174610-edc3ab29cdff/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69 h1:N4WAsrRIb+4U1yIwJO3FMrLnrr61ael894nygpViQTU= -github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/machine v0.16.1 h1:zrgroZounGVkxLmBqMyc1uT2GgapXVjIWHCfBf0udrA= -github.com/docker/machine v0.16.1/go.mod h1:I8mPNDeK1uH+JTcUU7X0ZW8KiYz0jyAgNaeSJ1rCfDI= +github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libnetwork v0.0.0-20180830151422-a9cd636e3789/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= +github.com/docker/machine v0.16.1-0.20190718054102-a555e4f7a8f5 h1:5OiV/JwT55JRKNJsM9HZrTlJH/TRp97Ee89ahtB78+w= +github.com/docker/machine v0.16.1-0.20190718054102-a555e4f7a8f5/go.mod h1:I8mPNDeK1uH+JTcUU7X0ZW8KiYz0jyAgNaeSJ1rCfDI= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs= github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhPhOPHULCQQDnGhRelpFWHMLhQVWDsS0v4= github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= +github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v0.0.0-20160318181535-f6a740d52f96/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e h1:ago6fNuQ6IhszPsXkeU7qRCyfsIX7L67WDybsAPkLl8= -github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415 h1:WSBJMqJbLxsn+bTCPyPYZfqHdJmc8MK4wrBjMft6BAM= +github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= -github.com/golang/glog v0.0.0-20141105023935-44145f04b68c h1:CbdkBQ1/PiAo0FYJhQGwASD8wrgNvTdf01g6+O9tNuA= -github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v0.0.0-20160127222235-bd3c8e81be01/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/cadvisor v0.33.2-0.20190411163913-9db8c7dee20a/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-containerregistry v0.0.0-20190318164241-019cdfc6adf9 h1:YVdfjqpMrLPm95Jc5JBFaEeGoPfhFxr43VW/UHQ2NVo= github.com/google/go-containerregistry v0.0.0-20190318164241-019cdfc6adf9/go.mod h1:yZAFP63pRshzrEYLXLGPmUt0Ay+2zdjmMN1loCnRLUk= -github.com/google/go-containerregistry v0.0.0-20190729175742-ef12d49c8daf h1:Wl/OmLiz1KZOQiAYUcttxkW01NbwzUGWy+whD7R58IQ= -github.com/google/go-containerregistry v0.0.0-20190729175742-ef12d49c8daf/go.mod h1:yZAFP63pRshzrEYLXLGPmUt0Ay+2zdjmMN1loCnRLUk= +github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v25 v25.0.2 h1:MqXE7nOlIF91NJ/PXAcvS2dC+XXCDbY7RvJzjyEPAoU= github.com/google/go-github/v25 v25.0.2/go.mod h1:6z5pC69qHtrPJ0sXPsj4BLnd82b+r6sLB7qcBoRZqpw= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 h1:ScAXWS+TR6MZKex+7Z8rneuSJH+FSDqd6ocQyl+ZHo4= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3 h1:siORttZ36U2R/WjiJuDz8znElWBiAlO9rVt+mqJt0Cc= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= 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-getter v1.3.0 h1:pFMSFlI9l5NaeuzkpE3L7BYk9qQ9juTAgXW/H0cqxcU= +github.com/hashicorp/go-getter v1.3.0/go.mod h1:/O1k/AizTN0QmfEKknCYGvICeyKUDqCYA8vvWtGWDeQ= 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= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 h1:OaRuzt9oCKNui8cCskZijoKUwe+aCuuCwvx1ox8FNyw= -github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1 h1:9j16AiR0R5hDbDBMzfUfIP9CUbbw6T8nYN4iZz3/wjg= +github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/heketi/heketi v0.0.0-20181109135656-558b29266ce0/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= +github.com/heketi/rest v0.0.0-20180404230133-aa6a65207413/go.mod h1:BeS3M108VzVlmAue3lv2WcGuPAX94/KN63MUURzbYSI= +github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= +github.com/heketi/utils v0.0.0-20170317161834-435bc5bdfa64/go.mod h1:RYlF4ghFZPPmk2TC5REt5OFwvfb6lzxFWrTWB+qs28s= github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI= github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E= github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8 h1:ARl0RuGZTqBOMXQIfXen0twVSJ8kMojd7ThJf4EBcrc= github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8/go.mod h1:sOC47ru8lB0DlU0EZ7BJ0KCP5rDqOvx0c/5K5ADm8H0= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 h1:FeeCi0I2Fu8kA8IXrdVPtGzym+mW9bzfj9f26EaES9k= -github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 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/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345 h1:XP1VL9iOZu4yz/rq8zj+yvB23XEY5erXRzp8JYmkWu0= github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345/go.mod h1:+c1/kUpg2zlkoWqTOvzDs36Wpbm3Gd1nlmtXAEB0WGU= -github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jteeuwen/go-bindata v0.0.0-20151023091102-a0ff2567cfb7/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kardianos/osext v0.0.0-20150410034420-8fef92e41e22/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 h1:YUrU1/jxRqnt0PSrKj1Uj/wEjk/fjnE80QFfi2Zlj7Q= github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169/go.mod h1:glhvuHOU9Hy7/8PwwdtnarXqLagOX0b/TbZx2zLMqEg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.0.0-20140812000539-f31442d60e51/go.mod h1:Bvhd+E3laJ0AVkG0c9rmtZcnhV0HQ3+c3YxxqTvc/gA= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.0.0-20130911015532-6807e777504f/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libopenstorage/openstorage v0.0.0-20170906232338-093a0c388875/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/libvirt/libvirt-go v3.4.0+incompatible h1:Cpyalgj1x8JIeTlL6SDYZBo7j8nY3+5XHqmi8DaunCk= github.com/libvirt/libvirt-go v3.4.0+incompatible/go.mod h1:34zsnB4iGeOv7Byj6qotuW8Ya4v4Tr43ttjz/F0wjLE= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= github.com/machine-drivers/docker-machine-driver-vmware v0.1.1 h1:+E1IKKk+6kaQrCPg6edJZ/zISZijuZTPnzy6RE4C/Ho= github.com/machine-drivers/docker-machine-driver-vmware v0.1.1/go.mod h1:ej014C83EmSnxJeJ8PtVb8OLJ91PJKO1Q8Y7sM5CK0o= -github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4 h1:YVH4JcnWs1z/qQ2Dg5BnGGQL8PcUOO97Sb5w7RyuBl4= github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b h1:idzeyUe3K4aU/SIZWMykIkJJyTD7CgDkxUQEjV07fno= -github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v0.0.0-20180605041737-f8471b0a71de/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mesos/mesos-go v0.0.9/go.mod h1:kPYCMQ9gsOXVAle1OsoY4I1+9kPu8GHkf88aV59fDr4= +github.com/mholt/caddy v0.0.0-20180213163048-2de495001514/go.mod h1:Wb1PlT4DAYSqOEd03MsqkdkXnTxA8v9pKjdpxbqM1kY= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v0.0.0-20160614162101-5d001d020961 h1:vX2vkMipgQZ8gfmAsFeZdcgmhHoB7jMo6chAtajG3AI= +github.com/miekg/dns v0.0.0-20160614162101-5d001d020961/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= +github.com/mistifyio/go-zfs v0.0.0-20151009155749-1b4ae6fb4e77/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 h1:kw1v0NlnN+GZcU8Ma8CLF2Zzgjfx95gs3/GN3vYAPpo= github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= -github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49 h1:kaWdlw4YogwkDl8CG+/VxhXkrL9uz3n1D9QBC2pEGLE= -github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/hyperkit v0.0.0-20171020124204-a12cd7250bcd h1:WDG9l//UGcGx4lqqEDY23+mRnQMKFY+8LD83OxQllRk= github.com/moby/hyperkit v0.0.0-20171020124204-a12cd7250bcd/go.mod h1:zGAVB/FkAf4ozkR8CCuj4LcVuErrNsj9APTDFvhOckw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mvdan/xurls v0.0.0-20160110113200-1b768d7c393a/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd h1:nEatQ6JnwCT9iYD5uqYUiFqq8tJGX25to8KVKXqya7k= github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca h1:dKRMHfduZ/ZqOHuYGk/0kkTIUbnyorkAfzLOp6Ts8pU= -github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pelletier/go-buffruneio v0.1.0 h1:ig6N9Cg71k/P+UUbhwdOFtJWz+qa8/3by7AzMprMWBM= -github.com/pelletier/go-buffruneio v0.1.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= -github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4 h1:tMVXZ04h5CqgTvMyA8IL1b9xlJz7G+mTcCsYi3WXRtA= -github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v0.0.0-20170604055404-372ad780f634/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20181113202123-f000fe11ece1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v0.0.0-20170621221121-4a2974bf1ee9/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= @@ -164,117 +367,300 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v0.0.0-20161223203901-3a8809bd8a80 h1:DQFOykp5w+HOykOMzd2yOX5P6ty58Ggiu2rthHgcNQg= github.com/pkg/profile v0.0.0-20161223203901-3a8809bd8a80/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6 h1:V8AT/I4KmIDRfObq0yBUvbD4DeaYmQY9GhC5sKl24Mo= github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/r2d4/external-storage v0.0.0-20171222174501-8c0e8605dc7b h1:+wokSDzl6kjfWhVQsBhFOC2t4TYfdLfRXfWorEg3KUE= -github.com/r2d4/external-storage v0.0.0-20171222174501-8c0e8605dc7b/go.mod h1:/UlUhYuWiiitqIPbAxyU96i/wDlBS8sRHX2lRN+ffgs= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/robfig/cron v0.0.0-20170309132418-df38d32658d8/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= -github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5 h1:+6eORf9Bt4C3Wjt91epyu6wvLW+P6+AEODb6uKgO+4g= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 h1:XRl74t6xHKI5EVIjDI5nPlHRq0bHED9/TjQuD8/UMkE= github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859/go.mod h1:yeYR4SlaRZJct6lwNRKR+qd0CocnxxWDE7Vh5dxsn/w= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db h1:lrOUn8raSZS/V52c7elGaEyuogqSkEo/Qj2Auo2G1ik= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.0.0-20150813023252-1b506fc7c24e/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= +github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sigma/go-inotify v0.0.0-20181102212354-c87b6cf5033d/go.mod h1:stlh9OsqBQSdwxTxX73mu41BBtRbIpZLQ7flcAoxAfo= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97 h1:Gv1HykSEG+RKWWWkM69nPrJKhE/EM2oFb1nBWogHNv8= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a h1:tPI5RnYZJhcXj0LhJ9pi7PS7gqOhuFR+4HEKyDz3BnQ= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/cobra v0.0.0-20180228053838-6644d46b81fa h1:w+PYzMV4Hrxj0nSHUxY881YFte8hst14ZZ0ZNL3mlEA= -github.com/spf13/cobra v0.0.0-20180228053838-6644d46b81fa/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80 h1:evyGXhHMrxKBDkdlSPv9HMWV2o53o+Ibhm28BGc0450= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= -github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v0.0.0-20160820190039-7fb2782df3d8/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vmware/govmomi v0.20.1/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/vmware/photon-controller-go-sdk v0.0.0-20170310013346-4a435daef6cc/go.mod h1:e6humHha1ekIwTCm+A5Qed5mG8V4JL+ChHcUOJ+L/8U= +github.com/xanzy/go-cloudstack v0.0.0-20160728180336-1e2cbf647e57/go.mod h1:s3eL3z5pNXF5FVybcT+LIVdId8pYn709yv6v5mrkrQE= github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 h1:KM4T3G70MiR+JtqplcYkNVoNz7pDwYaBxWBXQK804So= github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c h1:XZWnr3bsDQWAZg4Ne+cPoXRPILrNlPNQfxBuwLl43is= github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be h1:sRGd3e18izj1hQgF1hSvDOA8RPPnA2t4p8YeLZ/GdBU= github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 h1:Ucx5I1l1+TWXvqFmBigYu4Ub4MLvUuUU/whjoUvV95I= github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097/go.mod h1:lFZSWRIpCfE/pt91hHBBpV6+x87YlCjsp+aIR2qCPPU= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 h1:rlLehGeYg6jfoyz/eDqDU1iRXLKfR42nnNh57ytKEWo= -golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c h1:pcBdqVcrlT+A3i+tWsOROFONQyey9tisIQHI4xqVGLg= -golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20181004145325-8469e314837c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20170824195420-5d2fd3ccab98/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 h1:mBVYJnbrXLA/ZCBTCe7PtEgAUP+1bg92qTaFoPHdz+8= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.6 h1:YQye4a1JysUfXYB6VihDfxb4lxOAei0xS44yN+srOew= -gopkg.in/cheggaaa/pb.v1 v1.0.6/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.27 h1:kJdccidYzt3CaHD1crCFTS1hxyhSi059NhOFUf03YFo= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -k8s.io/api v0.0.0-20180712090710-2d6f90ab1293 h1:hROmpFC7JMobXFXMmD7ZKZLhDKvr1IKfFJoYS/45G/8= -k8s.io/api v0.0.0-20180712090710-2d6f90ab1293/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d h1:MZjlsu9igBoVPZkXpIGoxI6EonqNsXXZU7hhvfQLkd4= -k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/apiserver v0.0.0-20180914001516-67c892841170 h1:a9iLDj8v4x5/JpYsgKWSv3k6c5Q7M8dsyrAt4GLOzKQ= -k8s.io/apiserver v0.0.0-20180914001516-67c892841170/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w= -k8s.io/client-go v0.0.0-20180806134042-1f13a808da65 h1:kQX7jEIMYrWV9XqFN4usRaBLzCu7fd/qsCXxbgf3+9g= -k8s.io/client-go v0.0.0-20180806134042-1f13a808da65/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/kube-openapi v0.0.0-20180216212618-50ae88d24ede h1:YOWlONzJUq456SnNYPcK/org5asA+LU6AzNBm+l/04o= -k8s.io/kube-openapi v0.0.0-20180216212618-50ae88d24ede/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kubernetes v1.11.3 h1:49Pz+NOerox7nZ9F0m/fWv2MIuFDU5cDAoYMozurx1k= -k8s.io/kubernetes v1.11.3/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= +k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68= +k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30 h1:TRb4wNWoBVrH9plmkp2q86FIDppkbrEXdXlxU3a3BMI= +k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +k8s.io/kubernetes v1.15.0 h1:0P6jAdZ1cF5/wSc14HqHCjWlbnwYzmFJBYeXBezZEE0= +k8s.io/kubernetes v1.15.0/go.mod h1:3RE5ikMc73WK+dSxk4pQuQ6ZaJcPXiZX2dj98RcdCuM= +k8s.io/kubernetes/staging/src/k8s.io/api v0.0.0-20190623232353-8c3b7d7679cc h1:vZ5+77WP1yImZo23wc75vV5b5zCGq9gv484q8Yw5sBw= +k8s.io/kubernetes/staging/src/k8s.io/api v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:pU9hbGZc8Z6+6HlNLEFY1GiNGzcCykU1Glsd4vEea2U= +k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:Q49J/iUBV6A9nn8loyV72DK2EXhN8sqCR8FyfxIFDA4= +k8s.io/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20190623232353-8c3b7d7679cc h1:SHxaBZWgNouwsZCVg2+iffu0Um1ExSLPKgvO1drWShs= +k8s.io/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:rRBYbORqofLsn4/tsQWkeXkdKUoGrTfUwbI9s7NhU0Q= +k8s.io/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:0xlmg2F70Iaf7pdSDkfFQhWiyKh7eRqO0fBx4OvA4IA= +k8s.io/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:YZQFNMZSNiRALChwxrRkzjVrmmJWNlSl4StwOETTIYI= +k8s.io/kubernetes/staging/src/k8s.io/client-go v0.0.0-20190623232353-8c3b7d7679cc h1:NkZ6eBWe3aFn6wCHgMBPfcjVSji1Nz/EcwGpFQjcT0c= +k8s.io/kubernetes/staging/src/k8s.io/client-go v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:O+HAJNvEkq6MA64VSkhBp2oKeuSVWtTgc9O3z7AgDfA= +k8s.io/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:rQUOm/XLTGmz4tguTc3V1Ee8zCf5BZ2lCh7nv6dXTzA= +k8s.io/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20190623232353-8c3b7d7679cc h1:RvTiGzEJ1/k72+BZMjwkGCF6gYMBxn0zeeiE8Yu6f/I= +k8s.io/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:8RJmS4bkGaaevegssxZX5h3eMJzW3smzE67LISltg+k= +k8s.io/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:oFKBcitmDfPm+OpCoj4rfVSuHbWynjF3/L/sMV4tB0w= +k8s.io/kubernetes/staging/src/k8s.io/component-base v0.0.0-20190623232353-8c3b7d7679cc h1:WLHw9cDk+CO4nOmbXsU4twzxlJymyKjncV96XDFwkck= +k8s.io/kubernetes/staging/src/k8s.io/component-base v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:kUl6x7EkDsgIPSyB6dN6UIRqtofbZpoGp9RDYlqm1EY= +k8s.io/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:YrwDlnLsMEkKgyPt/gJOHrXoCpYIdDpcikarkQ1hubo= +k8s.io/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:5RWpGgZKzUcW9gCtmSVRq8maZkOetGv87HrohpTrnLI= +k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:ogOX4l9UCMfFGIF+FZqmsln4NtCGPqf9zTMCIlm2YX4= +k8s.io/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:o6aAFW1lCnr5CJm1riWnhQskrAHhyt8btyv5UHhgZ6c= +k8s.io/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:y0hpsQGN8h3HcNqYbpSZEH4yC1ohi45N35c8ma9yg6M= +k8s.io/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:/hbCTKdfutEO2iTQv8NuYcnAxd8Tuu4mMEymYv/EZHk= +k8s.io/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20190623232353-8c3b7d7679cc h1:Bsljf/3UDy91qqLkevAiq6y+wl0qJrkLjWfBCQs9rss= +k8s.io/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:Vg6Q3IDU3hfYMICKyb43lClOXWtCtOBh2o1FfuQw8mQ= +k8s.io/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:9UInPlSttlDwZBFNMAsqhTtl7zH00dE2M88B9Z0Ennc= +k8s.io/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:xlTRb77uaXbuT6evILwFescWPMENFKYGYj3a/kOjYQE= +k8s.io/kubernetes/staging/src/k8s.io/metrics v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:6Cs3k9ccbWbJo3CQOrGDu2QEVLwsWbBlu9HitjPhuSk= +k8s.io/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20190623232353-8c3b7d7679cc/go.mod h1:2LUaF4APkM/13Q3y9+NnAjBQrLPDy3IrJ0uKTS+zxP4= +k8s.io/repo-infra v0.0.0-20181204233714-00fe14e3d1a3/go.mod h1:+G1xBfZDfVFsm1Tj/HNCvg4QqWx8rJ2Fxpqr1rqp/gQ= +k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4= +k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +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= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.0+incompatible h1:qV3eFdgCp7Cp/ORjkJI9VBBEOntT+z385jLqdBtmgHA= +sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.0+incompatible/go.mod h1:qhqLyNwJC49PoUalmtzYb4s9fT8HOMBTLbTY1QoVOqI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190302045857-e85c7b244fd2/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= +vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/hack/jenkins/common.sh b/hack/jenkins/common.sh index 8c66c0c21d..288febe932 100755 --- a/hack/jenkins/common.sh +++ b/hack/jenkins/common.sh @@ -23,7 +23,7 @@ # 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 -# +# PARALLEL_COUNT: number of tests to run in parallel readonly TEST_ROOT="${HOME}/minikube-integration" @@ -76,6 +76,7 @@ gsutil -qm cp \ gsutil -qm cp "gs://minikube-builds/${MINIKUBE_LOCATION}/testdata"/* testdata/ + # Set the executable bit on the e2e binary and out binary export MINIKUBE_BIN="out/minikube-${OS_ARCH}" export E2E_BIN="out/e2e-${OS_ARCH}" @@ -83,7 +84,7 @@ chmod +x "${MINIKUBE_BIN}" "${E2E_BIN}" out/docker-machine-driver-* procs=$(pgrep "minikube-${OS_ARCH}|e2e-${OS_ARCH}" || true) if [[ "${procs}" != "" ]]; then - echo "ERROR: found stale test processes to kill:" + echo "Warning: found stale test processes to kill:" ps -f -p ${procs} || true kill ${procs} || true kill -9 ${procs} || true @@ -131,6 +132,13 @@ if type -P virsh; then | awk '{ print $2 }' \ | xargs -I {} sh -c "virsh -c qemu:///system destroy {}; virsh -c qemu:///system undefine {}" \ || true + virsh -c qemu:///system list --all \ + | grep Test \ + | awk '{ print $2 }' \ + | xargs -I {} sh -c "virsh -c qemu:///system destroy {}; virsh -c qemu:///system undefine {}" \ + || true + echo ">> Virsh VM list after clean up (should be empty) :" + virsh -c qemu:///system list --all || true fi if type -P vboxmanage; then @@ -140,6 +148,21 @@ if type -P vboxmanage; then | cut -d'"' -f2 \ | xargs -I {} sh -c "vboxmanage startvm {} --type emergencystop; vboxmanage unregistervm {} --delete" \ || true + vboxmanage list vms \ + | grep Test \ + | cut -d'"' -f2 \ + | xargs -I {} sh -c "vboxmanage startvm {} --type emergencystop; vboxmanage unregistervm {} --delete" \ + || true + + # remove inaccessible stale VMs https://github.com/kubernetes/minikube/issues/4872 + vboxmanage list vms \ + | grep inaccessible \ + | cut -d'"' -f3 \ + | xargs -I {} sh -c "vboxmanage startvm {} --type emergencystop; vboxmanage unregistervm {} --delete" \ + || true + + # list them again after clean up + vboxmanage list vms || true fi if type -P hdiutil; then @@ -151,6 +174,23 @@ if type -P hdiutil; then || true fi +# cleaning up stale hyperkits +if type -P hyperkit; then + # find all hyperkits excluding com.docker + hyper_procs=$(ps aux | grep hyperkit | grep -v com.docker | grep -v grep | grep -v osx_integration_tests_hyperkit.sh | awk '{print $2}' || true) + if [[ "${hyper_procs}" != "" ]]; then + echo "Found stale hyperkits test processes to kill : " + for p in $hyper_procs + do + echo "Killing stale hyperkit $p" + ps -f -p $p || true + kill $p || true + kill -9 $p || true + done + fi +fi + + if [[ "${VM_DRIVER}" == "hyperkit" ]]; then if [[ -e out/docker-machine-driver-hyperkit ]]; then sudo chown root:wheel out/docker-machine-driver-hyperkit || true @@ -162,9 +202,22 @@ kprocs=$(pgrep kubectl || true) if [[ "${kprocs}" != "" ]]; then echo "error: killing hung kubectl processes ..." ps -f -p ${kprocs} || true - ${SUDO_PREFIX} kill ${kprocs} || true + sudo -E kill ${kprocs} || true fi +# clean up none drivers binding on 8443 + none_procs=$(sudo lsof -i :8443 | tail -n +2 | awk '{print $2}' || true) + if [[ "${none_procs}" != "" ]]; then + echo "Found stale api servers listening on 8443 processes to kill: " + for p in $none_procs + do + echo "Kiling stale none driver: $p" + sudo -E ps -f -p $p || true + sudo -E kill $p || true + sudo -E kill -9 $p || true + done + fi + function cleanup_stale_routes() { local show="netstat -rn -f inet" local del="sudo route -n delete" @@ -198,7 +251,7 @@ echo ">> Starting ${E2E_BIN} at $(date)" ${SUDO_PREFIX}${E2E_BIN} \ -minikube-start-args="--vm-driver=${VM_DRIVER} ${EXTRA_START_ARGS}" \ -minikube-args="--v=10 --logtostderr ${EXTRA_ARGS}" \ - -test.v -test.timeout=90m -binary="${MINIKUBE_BIN}" && result=$? || result=$? + -test.v -test.timeout=100m -test.parallel=${PARALLEL_COUNT} -binary="${MINIKUBE_BIN}" && result=$? || result=$? echo ">> ${E2E_BIN} exited with ${result} at $(date)" echo "" diff --git a/hack/jenkins/linux_integration_tests_kvm.sh b/hack/jenkins/linux_integration_tests_kvm.sh index f63bdc31dc..e9df5eab4f 100755 --- a/hack/jenkins/linux_integration_tests_kvm.sh +++ b/hack/jenkins/linux_integration_tests_kvm.sh @@ -28,6 +28,7 @@ set -e OS_ARCH="linux-amd64" VM_DRIVER="kvm2" JOB_NAME="Linux-KVM" +PARALLEL_COUNT=4 # Download files and set permissions source ./common.sh diff --git a/hack/jenkins/linux_integration_tests_none.sh b/hack/jenkins/linux_integration_tests_none.sh index 83d4348058..3995367e68 100755 --- a/hack/jenkins/linux_integration_tests_none.sh +++ b/hack/jenkins/linux_integration_tests_none.sh @@ -30,6 +30,7 @@ OS_ARCH="linux-amd64" VM_DRIVER="none" JOB_NAME="Linux-None" EXTRA_ARGS="--bootstrapper=kubeadm" +PARALLEL_COUNT=1 SUDO_PREFIX="sudo -E " export KUBECONFIG="/root/.kube/config" diff --git a/hack/jenkins/linux_integration_tests_virtualbox.sh b/hack/jenkins/linux_integration_tests_virtualbox.sh index 455eb05918..13ba5ff0cd 100755 --- a/hack/jenkins/linux_integration_tests_virtualbox.sh +++ b/hack/jenkins/linux_integration_tests_virtualbox.sh @@ -28,6 +28,7 @@ set -e OS_ARCH="linux-amd64" VM_DRIVER="virtualbox" JOB_NAME="Linux-VirtualBox" +PARALLEL_COUNT=4 # Download files and set permissions source ./common.sh diff --git a/hack/jenkins/osx_cleanup_and_reboot.sh b/hack/jenkins/osx_cleanup_and_reboot.sh new file mode 100755 index 0000000000..503796c212 --- /dev/null +++ b/hack/jenkins/osx_cleanup_and_reboot.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +# 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. + +# Periodically cleanup and reboot if no Jenkins subprocesses are running. +set -uf -o pipefail + +PATH=/usr/local/bin:/sbin:/usr/local/sbin:$PATH + +exit_if_jenkins() { + jenkins=$(pgrep java) + if [[ "$jenkins" -- "" ]]; then + echo "no java, no jenkins" + return 0 + fi + pstree $jenkins | grep -v java && echo "jenkins is running..." && exit 1 +} + +exit_if_jenkins +echo "waiting to see if any jobs are coming in..." +sleep 15 +exit_if_jenkins +echo "doing it" +killall java +sudo rm -Rf ~jenkins/.minikube || echo "could not delete minikube" +sudo rm -Rf ~/jenkins/minikube-integration/* || true +sudo reboot diff --git a/hack/jenkins/osx_integration_tests_hyperkit.sh b/hack/jenkins/osx_integration_tests_hyperkit.sh index 302a43fad2..e8aba54783 100755 --- a/hack/jenkins/osx_integration_tests_hyperkit.sh +++ b/hack/jenkins/osx_integration_tests_hyperkit.sh @@ -31,7 +31,7 @@ VM_DRIVER="hyperkit" JOB_NAME="OSX-Hyperkit" EXTRA_ARGS="--bootstrapper=kubeadm" EXTRA_START_ARGS="" - +PARALLEL_COUNT=3 # Download files and set permissions source common.sh diff --git a/hack/jenkins/osx_integration_tests_virtualbox.sh b/hack/jenkins/osx_integration_tests_virtualbox.sh index efcdda72fa..00933b1c9a 100755 --- a/hack/jenkins/osx_integration_tests_virtualbox.sh +++ b/hack/jenkins/osx_integration_tests_virtualbox.sh @@ -29,6 +29,7 @@ OS_ARCH="darwin-amd64" VM_DRIVER="virtualbox" JOB_NAME="OSX-Virtualbox" EXTRA_ARGS="--bootstrapper=kubeadm" +PARALLEL_COUNT=3 # Download files and set permissions source common.sh diff --git a/hack/jenkins/release_build_and_upload.sh b/hack/jenkins/release_build_and_upload.sh index 086ba72484..3bb3f3d97c 100755 --- a/hack/jenkins/release_build_and_upload.sh +++ b/hack/jenkins/release_build_and_upload.sh @@ -37,7 +37,9 @@ cat Makefile | grep "VERSION_MINOR ?=" | grep $VERSION_MINOR cat Makefile | grep "VERSION_BUILD ?=" | grep $VERSION_BUILD # Build and upload -BUILD_IN_DOCKER=y make -j 16 all out/minikube-installer.exe out/minikube_${DEB_VERSION}.deb out/minikube-${RPM_VERSION}.rpm +BUILD_IN_DOCKER=y make -j 16 all out/minikube-installer.exe \ +out/minikube_${DEB_VERSION}.deb out/minikube-${RPM_VERSION}.rpm \ +out/docker-machine-driver-kvm2_${DEB_VERSION}.deb out/docker-machine-driver-kvm2-${RPM_VERSION}.rpm make checksum gsutil -m cp out/* gs://$BUCKET/releases/$TAGNAME/ diff --git a/hack/jenkins/windows_cleanup_and_reboot.bat b/hack/jenkins/windows_cleanup_and_reboot.bat new file mode 100644 index 0000000000..84dd6e907d --- /dev/null +++ b/hack/jenkins/windows_cleanup_and_reboot.bat @@ -0,0 +1,33 @@ +:: 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. + +:: Periodically cleanup and reboot if no Jenkins subprocesses are running. + +@echo off +call :jenkins +echo waiting to see if any jobs are coming in... +timeout 30 +call :jenkins +echo doing it +taskkill /IM putty.exe +taskkill /F /IM java.exe +powershell -Command "Stop-VM minikube" +powershell -Command "Delete-VM minikube" +rmdir /S /Q C:\Users\admin\.minikube +shutdown /r + +:jenkins +tasklist | find /i /n "e2e-windows-amd64.exe">NUL +if %ERRORLEVEL% == 0 exit 1 +exit /B 0 diff --git a/installers/linux/deb/kvm2_deb_template/DEBIAN/control b/installers/linux/deb/kvm2_deb_template/DEBIAN/control new file mode 100644 index 0000000000..49a6075b6a --- /dev/null +++ b/installers/linux/deb/kvm2_deb_template/DEBIAN/control @@ -0,0 +1,12 @@ +Package: docker-machine-driver-kvm2 +Version: --VERSION-- +Section: base +Priority: optional +Architecture: amd64 +Depends: libvirt0 (>= 1.3.1) +Recommends: minikube +Maintainer: Thomas Strömberg +Description: Machine driver for KVM + minikube uses Docker Machine to manage the Kubernetes VM so it benefits + from the driver plugin architecture that Docker Machine uses to provide + a consistent way to manage various VM providers. diff --git a/installers/linux/deb/minikube_deb_template/DEBIAN/control b/installers/linux/deb/minikube_deb_template/DEBIAN/control index 6c1a6a6aca..98a93a25b8 100644 --- a/installers/linux/deb/minikube_deb_template/DEBIAN/control +++ b/installers/linux/deb/minikube_deb_template/DEBIAN/control @@ -4,9 +4,9 @@ Section: base Priority: optional Architecture: amd64 Recommends: virtualbox -Maintainer: Aaron Prindle +Maintainer: Thomas Strömberg Description: Minikube - Minikube is a tool that makes it easy to run Kubernetes locally. - Minikube runs a single-node Kubernetes cluster inside a VM on your + minikube is a tool that makes it easy to run Kubernetes locally. + minikube runs a single-node Kubernetes cluster inside a VM on your laptop for users looking to try out Kubernetes or develop with it day-to-day. diff --git a/installers/linux/rpm/kvm2_rpm_template/docker-machine-driver-kvm2.spec b/installers/linux/rpm/kvm2_rpm_template/docker-machine-driver-kvm2.spec new file mode 100644 index 0000000000..372e7e18cc --- /dev/null +++ b/installers/linux/rpm/kvm2_rpm_template/docker-machine-driver-kvm2.spec @@ -0,0 +1,29 @@ +Name: docker-machine-driver-kvm2 +Version: --VERSION-- +Release: 0 +Summary: Machine driver for KVM +License: ASL 2.0 +Group: Development/Tools +URL: https://github.com/kubernetes/minikube +#Requires: + +# Needed for older versions of RPM +BuildRoot: %{_tmppath}%{name}-buildroot + +%description +Minikube uses Docker Machine to manage the Kubernetes VM so it benefits +from the driver plugin architecture that Docker Machine uses to provide +a consistent way to manage various VM providers. + +%prep +mkdir -p %{name}-%{version} +cd %{name}-%{version} +cp --OUT--/docker-machine-driver-kvm2 . + +%install +cd %{name}-%{version} +mkdir -p %{buildroot}%{_bindir} +install -m 755 docker-machine-driver-kvm2 %{buildroot}%{_bindir}/%{name} + +%files +%{_bindir}/%{name} diff --git a/netlify.toml b/netlify.toml index db1a94e699..6084cd18c0 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,17 +1,17 @@ [build] base = "site/" publish = "site/public/" -command = "hugo" +command = "pwd && cd themes/docsy && git submodule update -f --init && cd ../.. && hugo" [build.environment] -HUGO_VERSION = "0.55.0" +HUGO_VERSION = "0.55.6" [context.production.environment] HUGO_ENV = "production" HUGO_BASEURL = "https://minikube.sigs.k8s.io/" -[context.deploy-preview] -command = "hugo --enableGitInfo --buildFuture -b $DEPLOY_PRIME_URL" +#[context.deploy-preview] +#command = "hugo --enableGitInfo --buildFuture -b $DEPLOY_PRIME_URL" -[context.branch-deploy] -command = "hugo --enableGitInfo --buildFuture -b $DEPLOY_PRIME_URL" +#[context.branch-deploy] +#command = "hugo --enableGitInfo --buildFuture -b $DEPLOY_PRIME_URL" diff --git a/pkg/drivers/none/none.go b/pkg/drivers/none/none.go index 36bf694306..dd18634d4a 100644 --- a/pkg/drivers/none/none.go +++ b/pkg/drivers/none/none.go @@ -17,8 +17,10 @@ limitations under the License. package none import ( + "bytes" "fmt" "strings" + "time" "github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/state" @@ -29,6 +31,7 @@ import ( "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/util" ) const driverName = constants.DriverNone @@ -218,7 +221,29 @@ func (d *Driver) RunSSHCommandFromDriver() error { // stopKubelet idempotently stops the kubelet func stopKubelet(exec command.Runner) error { glog.Infof("stopping kubelet.service ...") - return exec.Run("sudo systemctl stop kubelet.service") + stop := func() error { + cmdStop := "sudo systemctl stop kubelet.service" + cmdCheck := "sudo systemctl show -p SubState kubelet" + err := exec.Run(cmdStop) + if err != nil { + glog.Errorf("temporary error for %q : %v", cmdStop, err) + } + var out bytes.Buffer + errStatus := exec.CombinedOutputTo(cmdCheck, &out) + if errStatus != nil { + glog.Errorf("temporary error: for %q : %v", cmdCheck, errStatus) + } + if !strings.Contains(out.String(), "dead") { + return fmt.Errorf("expected to kubelet to be dead but it got : %q", out) + } + return nil + } + + if err := util.RetryAfter(3, stop, 2*time.Second); err != nil { + return errors.Wrapf(err, "error stopping kubelet") + } + + return nil } // restartKubelet restarts the kubelet diff --git a/pkg/minikube/drivers/kvm/doc.go b/pkg/initflag/initflag.go similarity index 61% rename from pkg/minikube/drivers/kvm/doc.go rename to pkg/initflag/initflag.go index d15b5fab9d..806b8ba76b 100644 --- a/pkg/minikube/drivers/kvm/doc.go +++ b/pkg/initflag/initflag.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Kubernetes Authors All rights reserved. +Copyright 2019 The Kubernetes Authors All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,6 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kvm +package initflag -// doc... +import ( + "flag" +) + +func init() { + // Workaround for "ERROR: logging before flag.Parse" + // See: https://github.com/kubernetes/kubernetes/issues/17162 + fs := flag.NewFlagSet("", flag.ContinueOnError) + _ = fs.Parse([]string{}) + flag.CommandLine = fs +} diff --git a/pkg/minikube/assets/addons.go b/pkg/minikube/assets/addons.go index ef3da11ff4..fd4cdff499 100644 --- a/pkg/minikube/assets/addons.go +++ b/pkg/minikube/assets/addons.go @@ -220,12 +220,6 @@ var Addons = map[string]*Addon{ "ingress-dp.yaml", "0640", true), - MustBinAsset( - "deploy/addons/ingress/ingress-svc.yaml.tmpl", - constants.AddonsPath, - "ingress-svc.yaml", - "0640", - false), }, false, "ingress"), "metrics-server": NewAddon([]*BinAsset{ MustBinAsset( diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index 5da05cef9a..9e45a9f963 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -38,10 +38,10 @@ import ( "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/util" ) @@ -305,7 +305,7 @@ func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig) error { // by a CNI plugin which is usually started after minikube has been brought // up. Otherwise, minikube won't start, as "k8s-app" pods are not ready. componentsOnly := k8s.NetworkPlugin == "cni" - console.OutStyle(console.WaitingPods, "Verifying:") + out.T(out.WaitingPods, "Waiting for:") client, err := util.GetClient() if err != nil { return errors.Wrap(err, "k8s client") @@ -313,7 +313,7 @@ func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig) error { // Wait until the apiserver can answer queries properly. We don't care if the apiserver // pod shows up as registered, but need the webserver for all subsequent queries. - console.Out(" apiserver") + out.String(" apiserver") if err := k.waitForAPIServer(k8s); err != nil { return errors.Wrap(err, "waiting for apiserver") } @@ -323,13 +323,13 @@ func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig) error { continue } - console.Out(" %s", p.name) + out.String(" %s", p.name) selector := labels.SelectorFromSet(labels.Set(map[string]string{p.key: p.value})) if err := util.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { return errors.Wrap(err, fmt.Sprintf("waiting for %s=%s", p.key, p.value)) } } - console.OutLn("") + out.Ln("") return nil } @@ -483,7 +483,7 @@ func (k *Bootstrapper) UpdateCluster(cfg config.KubernetesConfig) error { _, images := constants.GetKubeadmCachedImages(cfg.ImageRepository, cfg.KubernetesVersion) if cfg.ShouldLoadCachedImages { if err := machine.LoadImages(k.c, images, constants.ImageCacheDir); err != nil { - console.Failure("Unable to load cached images: %v", err) + out.FailureT("Unable to load cached images: {{.error}}", out.V{"error": err}) } } r, err := cruntime.New(cruntime.Config{Type: cfg.ContainerRuntime, Socket: cfg.CRISocket}) diff --git a/pkg/minikube/bootstrapper/kubeadm/versions_test.go b/pkg/minikube/bootstrapper/kubeadm/versions_test.go index 3f7a8bb3f7..cc4ec232b6 100644 --- a/pkg/minikube/bootstrapper/kubeadm/versions_test.go +++ b/pkg/minikube/bootstrapper/kubeadm/versions_test.go @@ -111,28 +111,20 @@ func TestParseFeatureArgs(t *testing.T) { expectedComponentFeatureArgs string }{ { - description: "only kubeadm feature", - featureGates: "Auditing=true,SelfHosting=false", + description: "CoreDNS enabled", + featureGates: "CoreDNS=true", expectedKubeadmFeatureArgs: map[string]bool{ - "Auditing": true, - "SelfHosting": false, + "CoreDNS": true, }, expectedComponentFeatureArgs: "", }, { - description: "only component feature", - featureGates: "PodPriority=true,Accelerators=false", - expectedKubeadmFeatureArgs: map[string]bool{}, - expectedComponentFeatureArgs: "PodPriority=true,Accelerators=false", - }, - { - description: "between component and kubeadm feature", - featureGates: "Auditing=true,PodPriority=true,SelfHosting=false,Accelerators=false", + description: "CoreDNS disabled", + featureGates: "CoreDNS=false", expectedKubeadmFeatureArgs: map[string]bool{ - "Auditing": true, - "SelfHosting": false, + "CoreDNS": false, }, - expectedComponentFeatureArgs: "PodPriority=true,Accelerators=false", + expectedComponentFeatureArgs: "", }, } diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index 39d6e06c8b..cbf82a9947 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -20,6 +20,7 @@ import ( "encoding/json" "flag" "fmt" + "io/ioutil" "math" "net" "os/exec" @@ -29,6 +30,7 @@ import ( "time" "github.com/docker/machine/libmachine" + "github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/engine" "github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/mcnerror" @@ -37,11 +39,14 @@ import ( "github.com/docker/machine/libmachine/state" "github.com/golang/glog" "github.com/pkg/errors" + "github.com/shirou/gopsutil/cpu" + "github.com/shirou/gopsutil/disk" + "github.com/shirou/gopsutil/mem" "github.com/spf13/viper" cfg "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/registry" "k8s.io/minikube/pkg/util" pkgutil "k8s.io/minikube/pkg/util" @@ -72,12 +77,10 @@ func init() { // CacheISO downloads and caches ISO. func CacheISO(config cfg.MachineConfig) error { - if config.VMDriver != constants.DriverNone { - if err := config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO); err != nil { - return err - } + if localDriver(config.VMDriver) { + return nil } - return nil + return config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO) } // StartHost starts a host VM. @@ -100,14 +103,14 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) } if h.Driver.DriverName() != config.VMDriver { - console.Out("\n") - console.Warning("Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.", - config.VMDriver, cfg.GetMachineName(), h.Driver.DriverName()) - console.Warning("To switch drivers, you may create a new VM using `minikube start -p --vm-driver=%s`", config.VMDriver) - console.Warning("Alternatively, you may delete the existing VM using `minikube delete -p %s`", cfg.GetMachineName()) - console.Out("\n") + out.T(out.Empty, "\n") + out.WarningT(`Ignoring --vm-driver={{.driver_name}}, as the existing "{{.profile_name}}" VM was created using the {{.driver_name2}} driver.`, + out.V{"driver_name": config.VMDriver, "profile_name": cfg.GetMachineName(), "driver_name2": h.Driver.DriverName()}) + out.WarningT("To switch drivers, you may create a new VM using `minikube start -p --vm-driver={{.driver_name}}`", out.V{"driver_name": config.VMDriver}) + out.WarningT("Alternatively, you may delete the existing VM using `minikube delete -p {{.profile_name}}`", out.V{"profile_name": cfg.GetMachineName()}) + out.T(out.Empty, "\n") } else if exists && cfg.GetMachineName() == constants.DefaultMachineName { - console.OutStyle(console.Tip, "Tip: Use 'minikube start -p ' to create a new cluster, or 'minikube delete' to delete this one.") + out.T(out.Tip, "Tip: Use 'minikube start -p ' to create a new cluster, or 'minikube delete' to delete this one.") } s, err := h.Driver.GetState() @@ -117,9 +120,9 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) } if s == state.Running { - console.OutStyle(console.Running, "Re-using the currently running %s VM for %q ...", h.Driver.DriverName(), cfg.GetMachineName()) + out.T(out.Running, `Using the running {{.driver_name}} "{{.profile_name}}" VM ...`, out.V{"driver_name": h.Driver.DriverName(), "profile_name": cfg.GetMachineName()}) } else { - console.OutStyle(console.Restarting, "Restarting existing %s VM for %q ...", h.Driver.DriverName(), cfg.GetMachineName()) + out.T(out.Restarting, `Starting existing {{.driver_name}} VM for "{{.profile_name}}" ...`, out.V{"driver_name": h.Driver.DriverName(), "profile_name": cfg.GetMachineName()}) if err := h.Driver.Start(); err != nil { return nil, errors.Wrap(err, "start") } @@ -131,6 +134,7 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) e := engineOptions(config) glog.Infof("engine options: %+v", e) + out.T(out.Waiting, "Waiting for the host to be provisioned ...") err = configureHost(h, e) if err != nil { return nil, err @@ -138,23 +142,32 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) return h, nil } +// localDriver returns whether or not the driver should be considered local +func localDriver(name string) bool { + if name == constants.DriverNone || name == constants.DriverMock { + return true + } + return false +} + // configureHost handles any post-powerup configuration required func configureHost(h *host.Host, e *engine.Options) error { - // Slightly counter-intuitive, but this is what DetectProvisioner & ConfigureAuth block on. - console.OutStyle(console.Waiting, "Waiting for SSH access ...") - + glog.Infof("configureHost: %T %+v", h, h) if len(e.Env) > 0 { h.HostOptions.EngineOptions.Env = e.Env + glog.Infof("Detecting provisioner ...") provisioner, err := provision.DetectProvisioner(h.Driver) if err != nil { return errors.Wrap(err, "detecting provisioner") } + glog.Infof("Provisioning: %+v", *h.HostOptions) if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions); err != nil { return errors.Wrap(err, "provision") } } - if h.Driver.DriverName() != constants.DriverNone { + if !localDriver(h.Driver.DriverName()) { + glog.Infof("Configuring auth for driver %s ...", h.Driver.DriverName()) if err := h.ConfigureAuth(); err != nil { return &util.RetriableError{Err: errors.Wrap(err, "Error configuring auth on host")} } @@ -213,21 +226,22 @@ func adjustGuestClock(h hostRunner, t time.Time) error { } // trySSHPowerOff runs the poweroff command on the guest VM to speed up deletion -func trySSHPowerOff(h *host.Host) { +func trySSHPowerOff(h *host.Host) error { s, err := h.Driver.GetState() if err != nil { glog.Warningf("unable to get state: %v", err) - return + return err } if s != state.Running { glog.Infof("host is in state %s", s) - return + return nil } - console.OutStyle(console.Shutdown, "Powering off %q via SSH ...", cfg.GetMachineName()) + out.T(out.Shutdown, `Powering off "{{.profile_name}}" via SSH ...`, out.V{"profile_name": cfg.GetMachineName()}) out, err := h.RunSSHCommand("sudo poweroff") // poweroff always results in an error, since the host disconnects. glog.Infof("poweroff result: out=%s, err=%v", out, err) + return nil } // StopHost stops the host VM, saving state to disk. @@ -236,7 +250,15 @@ func StopHost(api libmachine.API) error { if err != nil { return errors.Wrapf(err, "load") } - console.OutStyle(console.Stopping, "Stopping %q in %s ...", cfg.GetMachineName(), host.DriverName) + + out.T(out.Stopping, `Stopping "{{.profile_name}}" in {{.driver_name}} ...`, out.V{"profile_name": cfg.GetMachineName(), "driver_name": host.DriverName}) + if host.DriverName == constants.DriverHyperv { + glog.Infof("As there are issues with stopping Hyper-V VMs using API, trying to shut down using SSH") + if err := trySSHPowerOff(host); err != nil { + return errors.Wrap(err, "ssh power off") + } + } + if err := host.Stop(); err != nil { alreadyInStateError, ok := err.(mcnerror.ErrHostAlreadyInState) if ok && alreadyInStateError.State == state.Stopped { @@ -255,10 +277,12 @@ func DeleteHost(api libmachine.API) error { } // This is slow if SSH is not responding, but HyperV hangs otherwise, See issue #2914 if host.Driver.DriverName() == constants.DriverHyperv { - trySSHPowerOff(host) + if err := trySSHPowerOff(host); err != nil { + glog.Infof("Unable to power off minikube because the host was not found.") + } } - console.OutStyle(console.DeletingHost, "Deleting %q from %s ...", cfg.GetMachineName(), host.DriverName) + out.T(out.DeletingHost, `Deleting "{{.profile_name}}" in {{.driver_name}} ...`, out.V{"profile_name": cfg.GetMachineName(), "driver_name": host.DriverName}) if err := host.Driver.Remove(); err != nil { return errors.Wrap(err, "host remove") } @@ -318,41 +342,96 @@ func engineOptions(config cfg.MachineConfig) *engine.Options { return &o } -func preCreateHost(config *cfg.MachineConfig) { - switch config.VMDriver { - case constants.DriverKvmOld: - if viper.GetBool(cfg.ShowDriverDeprecationNotification) { - console.Warning(`The kvm driver is deprecated and support for it will be removed in a future release. - Please consider switching to the kvm2 driver, which is intended to replace the kvm driver. - See https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver for more information. - To disable this message, run [minikube config set ShowDriverDeprecationNotification false]`) - } - case constants.DriverXhyve: - if viper.GetBool(cfg.ShowDriverDeprecationNotification) { - console.Warning(`The xhyve driver is deprecated and support for it will be removed in a future release. -Please consider switching to the hyperkit driver, which is intended to replace the xhyve driver. -See https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver for more information. -To disable this message, run [minikube config set ShowDriverDeprecationNotification false]`) - } - case constants.DriverVmwareFusion: - if viper.GetBool(cfg.ShowDriverDeprecationNotification) { - console.Warning(`The vmwarefusion driver is deprecated and support for it will be removed in a future release. - Please consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver. - See https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information. - To disable this message, run [minikube config set ShowDriverDeprecationNotification false]`) - } +type hostInfo struct { + Memory int + CPUs int + DiskSize int +} + +func megs(bytes uint64) int { + return int(bytes / 1024 / 1024) +} + +func getHostInfo() (*hostInfo, error) { + i, err := cpu.Info() + if err != nil { + glog.Warningf("Unable to get cpu info: %v", err) + return nil, err } + v, err := mem.VirtualMemory() + if err != nil { + glog.Warningf("Unable to get mem info: %v", err) + return nil, err + } + d, err := disk.Usage("/") + if err != nil { + glog.Warningf("Unable to get disk info: %v", err) + return nil, err + } + + var info hostInfo + info.CPUs = len(i) + info.Memory = megs(v.Total) + info.DiskSize = megs(d.Total) + return &info, nil +} + +// showLocalOsRelease shows systemd information about the current linux distribution, on the local host +func showLocalOsRelease() { + osReleaseOut, err := ioutil.ReadFile("/etc/os-release") + if err != nil { + glog.Errorf("ReadFile: %v", err) + return + } + + osReleaseInfo, err := provision.NewOsRelease(osReleaseOut) + if err != nil { + glog.Errorf("NewOsRelease: %v", err) + return + } + + out.T(out.Provisioner, "OS release is {{.pretty_name}}", out.V{"pretty_name": osReleaseInfo.PrettyName}) +} + +// showRemoteOsRelease shows systemd information about the current linux distribution, on the remote VM +func showRemoteOsRelease(driver drivers.Driver) { + provisioner, err := provision.DetectProvisioner(driver) + if err != nil { + glog.Errorf("DetectProvisioner: %v", err) + return + } + + osReleaseInfo, err := provisioner.GetOsReleaseInfo() + if err != nil { + glog.Errorf("GetOsReleaseInfo: %v", err) + return + } + + glog.Infof("Provisioned with %s", osReleaseInfo.PrettyName) } func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) { - preCreateHost(&config) - console.OutStyle(console.StartingVM, "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...", config.VMDriver, config.CPUs, config.Memory, config.DiskSize) + if config.VMDriver == constants.DriverVmwareFusion && viper.GetBool(cfg.ShowDriverDeprecationNotification) { + out.WarningT(`The vmwarefusion driver is deprecated and support for it will be removed in a future release. + Please consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver. + See https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information. + To disable this message, run [minikube config set ShowDriverDeprecationNotification false]`) + } + if !localDriver(config.VMDriver) { + out.T(out.StartingVM, "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...", out.V{"driver_name": config.VMDriver, "number_of_cpus": config.CPUs, "memory_size": config.Memory, "disk_size": config.DiskSize}) + } else { + info, err := getHostInfo() + if err == nil { + out.T(out.StartingNone, "Running on localhost (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...", out.V{"number_of_cpus": info.CPUs, "memory_size": info.Memory, "disk_size": info.DiskSize}) + } + } + def, err := registry.Driver(config.VMDriver) if err != nil { if err == registry.ErrDriverNotFound { - exit.Usage("unsupported driver: %s", config.VMDriver) + return nil, fmt.Errorf("unsupported driver: %s", config.VMDriver) } - exit.WithError("error getting driver", err) + return nil, errors.Wrap(err, "error getting driver") } driver := def.ConfigCreator(config) @@ -376,6 +455,12 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error return nil, errors.Wrap(err, "create") } + if !localDriver(config.VMDriver) { + showRemoteOsRelease(h.Driver) + } else { + showLocalOsRelease() + } + if err := api.Save(h); err != nil { return nil, errors.Wrap(err, "save") } @@ -407,8 +492,6 @@ func GetHostDockerEnv(api libmachine.API) (map[string]string, error) { // GetVMHostIP gets the ip address to be used for mapping host -> VM and VM -> host func GetVMHostIP(host *host.Host) (net.IP, error) { switch host.DriverName { - case constants.DriverKvmOld: - return net.ParseIP("192.168.42.1"), nil case constants.DriverKvm2: return net.ParseIP("192.168.39.1"), nil case constants.DriverHyperv: @@ -432,7 +515,7 @@ func GetVMHostIP(host *host.Host) (net.IP, error) { return []byte{}, errors.Wrap(err, "Error getting VM/Host IP address") } return ip, nil - case constants.DriverXhyve, constants.DriverHyperkit: + case constants.DriverHyperkit: return net.ParseIP("192.168.64.1"), nil case constants.DriverVmware: vmIPString, err := host.Driver.GetIP() @@ -512,6 +595,6 @@ func EnsureMinikubeRunningOrExit(api libmachine.API, exitStatus int) { exit.WithError("Error getting machine status", err) } if s != state.Running.String() { - exit.WithCode(exit.Unavailable, "minikube is not running, so the service cannot be accessed") + exit.WithCodeT(exit.Unavailable, "minikube is not running, so the service cannot be accessed") } } diff --git a/pkg/minikube/cluster/cluster_test.go b/pkg/minikube/cluster/cluster_test.go index db4b88441d..bae331fd11 100644 --- a/pkg/minikube/cluster/cluster_test.go +++ b/pkg/minikube/cluster/cluster_test.go @@ -37,14 +37,40 @@ type MockDownloader struct{} func (d MockDownloader) GetISOFileURI(isoURL string) string { return "" } func (d MockDownloader) CacheMinikubeISOFromURL(isoURL string) error { return nil } +func createMockDriverHost(c config.MachineConfig) interface{} { + return nil +} + +func RegisterMockDriver(t *testing.T) { + t.Helper() + _, err := registry.Driver(constants.DriverMock) + // Already registered + if err == nil { + return + } + err = registry.Register(registry.DriverDef{ + Name: constants.DriverMock, + Builtin: true, + ConfigCreator: createMockDriverHost, + DriverCreator: func() drivers.Driver { + return &tests.MockDriver{T: t} + }, + }) + if err != nil { + t.Fatalf("register failed: %v", err) + } +} + var defaultMachineConfig = config.MachineConfig{ - VMDriver: constants.DefaultVMDriver, + VMDriver: constants.DriverMock, MinikubeISO: constants.DefaultISOURL, Downloader: MockDownloader{}, + DockerEnv: []string{"MOCK_MAKE_IT_PROVISION=true"}, } func TestCreateHost(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) exists, _ := api.Exists(config.GetMachineName()) if exists { @@ -54,9 +80,12 @@ func TestCreateHost(t *testing.T) { if err != nil { t.Fatalf("Error creating host: %v", err) } - exists, _ = api.Exists(config.GetMachineName()) + exists, err = api.Exists(config.GetMachineName()) + if err != nil { + t.Fatalf("exists failed for %q: %v", config.GetMachineName(), err) + } if !exists { - t.Fatal("Machine does not exist, but should.") + t.Fatalf("%q does not exist, but should.", config.GetMachineName()) } h, err := api.Load(config.GetMachineName()) @@ -82,7 +111,8 @@ func TestCreateHost(t *testing.T) { } func TestStartHostExists(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) // Create an initial host. _, err := createHost(api, defaultMachineConfig) if err != nil { @@ -101,10 +131,10 @@ func TestStartHostExists(t *testing.T) { // This should pass without calling Create because the host exists already. h, err := StartHost(api, defaultMachineConfig) if err != nil { - t.Fatal("Error starting host.") + t.Fatalf("Error starting host: %v", err) } if h.Name != config.GetMachineName() { - t.Fatalf("Machine created with incorrect name: %s", h.Name) + t.Fatalf("GetMachineName()=%q, want %q", config.GetMachineName(), h.Name) } if s, _ := h.Driver.GetState(); s != state.Running { t.Fatalf("Machine not started.") @@ -115,13 +145,14 @@ func TestStartHostExists(t *testing.T) { } func TestStartStoppedHost(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) // Create an initial host. h, err := createHost(api, defaultMachineConfig) if err != nil { t.Fatalf("Error creating host: %v", err) } - d := tests.MockDriver{} + d := tests.MockDriver{T: t} h.Driver = &d d.CurrentState = state.Stopped @@ -149,7 +180,8 @@ func TestStartStoppedHost(t *testing.T) { } func TestStartHost(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) md := &tests.MockDetector{Provisioner: &tests.MockProvisioner{}} provision.SetDetector(md) @@ -159,7 +191,7 @@ func TestStartHost(t *testing.T) { t.Fatal("Error starting host.") } if h.Name != config.GetMachineName() { - t.Fatalf("Machine created with incorrect name: %s", h.Name) + t.Fatalf("GetMachineName()=%q, want %q", config.GetMachineName(), h.Name) } if exists, _ := api.Exists(h.Name); !exists { t.Fatal("Machine not saved.") @@ -176,7 +208,8 @@ func TestStartHost(t *testing.T) { } func TestStartHostConfig(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) md := &tests.MockDetector{Provisioner: &tests.MockProvisioner{}} provision.SetDetector(md) @@ -208,14 +241,16 @@ func TestStartHostConfig(t *testing.T) { } func TestStopHostError(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) if err := StopHost(api); err == nil { t.Fatal("An error should be thrown when stopping non-existing machine.") } } func TestStopHost(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) h, err := createHost(api, defaultMachineConfig) if err != nil { t.Errorf("createHost failed: %v", err) @@ -230,7 +265,8 @@ func TestStopHost(t *testing.T) { } func TestDeleteHost(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) if _, err := createHost(api, defaultMachineConfig); err != nil { t.Errorf("createHost failed: %v", err) } @@ -241,14 +277,14 @@ func TestDeleteHost(t *testing.T) { } func TestDeleteHostErrorDeletingVM(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) h, err := createHost(api, defaultMachineConfig) if err != nil { t.Errorf("createHost failed: %v", err) } - d := &tests.MockDriver{RemoveError: true} - + d := &tests.MockDriver{RemoveError: true, T: t} h.Driver = d if err := DeleteHost(api); err == nil { @@ -257,7 +293,8 @@ func TestDeleteHostErrorDeletingVM(t *testing.T) { } func TestDeleteHostErrorDeletingFiles(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) api.RemoveError = true if _, err := createHost(api, defaultMachineConfig); err != nil { t.Errorf("createHost failed: %v", err) @@ -269,7 +306,8 @@ func TestDeleteHostErrorDeletingFiles(t *testing.T) { } func TestGetHostStatus(t *testing.T) { - api := tests.NewMockAPI() + RegisterMockDriver(t) + api := tests.NewMockAPI(t) checkState := func(expected string) { s, err := GetHostStatus(api) @@ -296,10 +334,11 @@ func TestGetHostStatus(t *testing.T) { } func TestGetHostDockerEnv(t *testing.T) { + RegisterMockDriver(t) tempDir := tests.MakeTempDir() defer os.RemoveAll(tempDir) - api := tests.NewMockAPI() + api := tests.NewMockAPI(t) h, err := createHost(api, defaultMachineConfig) if err != nil { t.Fatalf("Error creating host: %v", err) @@ -308,6 +347,7 @@ func TestGetHostDockerEnv(t *testing.T) { BaseDriver: drivers.BaseDriver{ IPAddress: "127.0.0.1", }, + T: t, } h.Driver = d @@ -332,7 +372,7 @@ func TestGetHostDockerEnvIPv6(t *testing.T) { tempDir := tests.MakeTempDir() defer os.RemoveAll(tempDir) - api := tests.NewMockAPI() + api := tests.NewMockAPI(t) h, err := createHost(api, defaultMachineConfig) if err != nil { t.Fatalf("Error creating host: %v", err) @@ -341,6 +381,7 @@ func TestGetHostDockerEnvIPv6(t *testing.T) { BaseDriver: drivers.BaseDriver{ IPAddress: "fe80::215:5dff:fe00:a903", }, + T: t, } h.Driver = d @@ -357,9 +398,9 @@ func TestGetHostDockerEnvIPv6(t *testing.T) { } func TestCreateSSHShell(t *testing.T) { - api := tests.NewMockAPI() + api := tests.NewMockAPI(t) - s, _ := tests.NewSSHServer() + s, _ := tests.NewSSHServer(t) port, err := s.Start() if err != nil { t.Fatalf("Error starting ssh server: %v", err) @@ -372,6 +413,7 @@ func TestCreateSSHShell(t *testing.T) { IPAddress: "127.0.0.1", SSHKeyPath: "", }, + T: t, } api.Hosts[config.GetMachineName()] = &host.Host{Driver: d} diff --git a/pkg/minikube/cluster/default_drivers.go b/pkg/minikube/cluster/default_drivers.go index e45a101449..99dfe368f7 100644 --- a/pkg/minikube/cluster/default_drivers.go +++ b/pkg/minikube/cluster/default_drivers.go @@ -20,12 +20,10 @@ import ( // Import all the default drivers _ "k8s.io/minikube/pkg/minikube/drivers/hyperkit" _ "k8s.io/minikube/pkg/minikube/drivers/hyperv" - _ "k8s.io/minikube/pkg/minikube/drivers/kvm" _ "k8s.io/minikube/pkg/minikube/drivers/kvm2" _ "k8s.io/minikube/pkg/minikube/drivers/none" _ "k8s.io/minikube/pkg/minikube/drivers/parallels" _ "k8s.io/minikube/pkg/minikube/drivers/virtualbox" _ "k8s.io/minikube/pkg/minikube/drivers/vmware" _ "k8s.io/minikube/pkg/minikube/drivers/vmwarefusion" - _ "k8s.io/minikube/pkg/minikube/drivers/xhyve" ) diff --git a/pkg/minikube/config/config.go b/pkg/minikube/config/config.go index 7a80446423..11268ec138 100644 --- a/pkg/minikube/config/config.go +++ b/pkg/minikube/config/config.go @@ -50,6 +50,11 @@ const ( ShowBootstrapperDeprecationNotification = "ShowBootstrapperDeprecationNotification" ) +var ( + // ErrKeyNotFound is the error returned when a key doesn't exist in the config file + ErrKeyNotFound = errors.New("specified key could not be found in config") +) + // MinikubeConfig represents minikube config type MinikubeConfig map[string]interface{} @@ -66,12 +71,30 @@ func get(name string, config MinikubeConfig) (string, error) { if val, ok := config[name]; ok { return fmt.Sprintf("%v", val), nil } - return "", errors.New("specified key could not be found in config") + return "", ErrKeyNotFound +} + +// WriteConfig writes a minikube config to the JSON file +func WriteConfig(configFile string, m MinikubeConfig) error { + f, err := os.Create(configFile) + if err != nil { + return fmt.Errorf("create %s: %s", configFile, err) + } + defer f.Close() + err = encode(f, m) + if err != nil { + return fmt.Errorf("encode %s: %s", configFile, err) + } + return nil } // ReadConfig reads in the JSON minikube config func ReadConfig() (MinikubeConfig, error) { - f, err := os.Open(constants.ConfigFile) + return readConfig(constants.ConfigFile) +} + +func readConfig(configFile string) (MinikubeConfig, error) { + f, err := os.Open(configFile) if err != nil { if os.IsNotExist(err) { return make(map[string]interface{}), nil @@ -94,8 +117,20 @@ func decode(r io.Reader) (MinikubeConfig, error) { return data, err } +func encode(w io.Writer, m MinikubeConfig) error { + b, err := json.MarshalIndent(m, "", " ") + if err != nil { + return err + } + + _, err = w.Write(b) + + return err +} + // GetMachineName gets the machine name for the VM func GetMachineName() string { + // REFACTOR NECESSARY: This function should not rely on globals. if viper.GetString(MachineProfile) == "" { return constants.DefaultMachineName } @@ -109,7 +144,7 @@ func Load() (*Config, error) { // Loader loads the kubernetes and machine config based on the machine profile name type Loader interface { - LoadConfigFromFile(profile string) (*Config, error) + LoadConfigFromFile(profile string, miniHome ...string) (*Config, error) } type simpleConfigLoader struct{} @@ -117,10 +152,10 @@ type simpleConfigLoader struct{} // DefaultLoader is the default config loader var DefaultLoader Loader = &simpleConfigLoader{} -func (c *simpleConfigLoader) LoadConfigFromFile(profile string) (*Config, error) { +func (c *simpleConfigLoader) LoadConfigFromFile(profile string, miniHome ...string) (*Config, error) { var cc Config - path := constants.GetProfileFile(profile) + path := constants.GetProfileFile(profile, miniHome...) if _, err := os.Stat(path); os.IsNotExist(err) { return nil, err diff --git a/pkg/minikube/config/config_test.go b/pkg/minikube/config/config_test.go index ecc13c5ce7..b6390a2ae3 100644 --- a/pkg/minikube/config/config_test.go +++ b/pkg/minikube/config/config_test.go @@ -18,6 +18,8 @@ package config import ( "bytes" + "io/ioutil" + "os" "reflect" "testing" @@ -46,10 +48,10 @@ var configTestCases = []configTestCase{ "log_dir": "/etc/hosts", "show-libmachine-logs": true, "v": 5, - "vm-driver": "kvm" + "vm-driver": "kvm2" }`, config: map[string]interface{}{ - "vm-driver": constants.DriverKvmOld, + "vm-driver": constants.DriverKvm2, "cpus": 4, "disk-size": "20g", "v": 5, @@ -60,7 +62,7 @@ var configTestCases = []configTestCase{ }, } -func TestReadConfig(t *testing.T) { +func Test_decode(t *testing.T) { for _, tt := range configTestCases { r := bytes.NewBufferString(tt.data) config, err := decode(r) @@ -70,7 +72,7 @@ func TestReadConfig(t *testing.T) { } } -func TestGet(t *testing.T) { +func Test_get(t *testing.T) { cfg := `{ "key": "val" }` @@ -101,3 +103,87 @@ func TestGet(t *testing.T) { } } } + +func Test_readConfig(t *testing.T) { + // non existing file + mkConfig, err := readConfig("non_existing_file") + if err != nil { + t.Fatalf("Error not exepected but got %v", err) + } + + if len(mkConfig) != 0 { + t.Errorf("Expected empty map but got %v", mkConfig) + } + + // invalid config file + mkConfig, err = readConfig("./testdata/.minikube/config/invalid_config.json") + if err == nil { + t.Fatalf("Error expected but got none") + } + + if mkConfig != nil { + t.Errorf("Expected nil but got %v", mkConfig) + } + + // valid config file + mkConfig, err = readConfig("./testdata/.minikube/config/valid_config.json") + if err != nil { + t.Fatalf("Error not expected but got %v", err) + } + + expectedConfig := map[string]interface{}{ + "vm-driver": constants.DriverKvm2, + "cpus": 4, + "disk-size": "20g", + "show-libmachine-logs": true, + "log_dir": "/etc/hosts", + } + + if reflect.DeepEqual(expectedConfig, mkConfig) || err != nil { + t.Errorf("Did not read config correctly,\n\n wanted %+v, \n\n got %+v", expectedConfig, mkConfig) + } +} + +func TestWriteConfig(t *testing.T) { + configFile, err := ioutil.TempFile("/tmp", "configTest") + if err != nil { + t.Fatalf("Error not expected but got %v", err) + } + + cfg := map[string]interface{}{ + "vm-driver": constants.DriverKvm2, + "cpus": 4, + "disk-size": "20g", + "show-libmachine-logs": true, + "log_dir": "/etc/hosts", + } + + err = WriteConfig(configFile.Name(), cfg) + if err != nil { + t.Fatalf("Error not expected but got %v", err) + } + defer os.Remove(configFile.Name()) + + mkConfig, err := readConfig(configFile.Name()) + if err != nil { + t.Fatalf("Error not expected but got %v", err) + } + + if reflect.DeepEqual(cfg, mkConfig) || err != nil { + t.Errorf("Did not read config correctly,\n\n wanted %+v, \n\n got %+v", cfg, mkConfig) + } +} + +func Test_encode(t *testing.T) { + var b bytes.Buffer + for _, tt := range configTestCases { + err := encode(&b, tt.config) + if err != nil { + t.Errorf("Error encoding: %v", err) + } + 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()) + } + b.Reset() + } +} diff --git a/pkg/minikube/config/profile.go b/pkg/minikube/config/profile.go new file mode 100644 index 0000000000..bd56d070bd --- /dev/null +++ b/pkg/minikube/config/profile.go @@ -0,0 +1,84 @@ +/* +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 config + +import ( + "io/ioutil" + "path/filepath" + + "k8s.io/minikube/pkg/minikube/constants" +) + +// isValid checks if the profile has the essential info needed for a profile +func (p *Profile) isValid() bool { + if p.Config.MachineConfig.VMDriver == "" { + return false + } + if p.Config.KubernetesConfig.KubernetesVersion == "" { + return false + } + return true +} + +// ListProfiles returns all valid and invalid (if any) minikube profiles +// invalidPs are the profiles that have a directory or config file but not usable +// invalidPs would be suggeted to be deleted +func ListProfiles(miniHome ...string) (validPs []*Profile, inValidPs []*Profile, err error) { + pDirs, err := profileDirs(miniHome...) + if err != nil { + return nil, nil, err + } + for _, n := range pDirs { + p, err := loadProfile(n, miniHome...) + if err != nil { + inValidPs = append(inValidPs, p) + continue + } + if !p.isValid() { + inValidPs = append(inValidPs, p) + continue + } + validPs = append(validPs, p) + } + return validPs, inValidPs, nil +} + +// loadProfile loads type Profile based on its name +func loadProfile(name string, miniHome ...string) (*Profile, error) { + cfg, err := DefaultLoader.LoadConfigFromFile(name, miniHome...) + p := &Profile{ + Name: name, + Config: cfg, + } + return p, err +} + +// profileDirs gets all the folders in the user's profiles folder regardless of valid or invalid config +func profileDirs(miniHome ...string) (dirs []string, err error) { + miniPath := constants.GetMinipath() + if len(miniHome) > 0 { + miniPath = miniHome[0] + } + pRootDir := filepath.Join(miniPath, "profiles") + items, err := ioutil.ReadDir(pRootDir) + for _, f := range items { + if f.IsDir() { + dirs = append(dirs, f.Name()) + } + } + return dirs, err +} diff --git a/pkg/minikube/config/profile_test.go b/pkg/minikube/config/profile_test.go new file mode 100644 index 0000000000..ac96602ee6 --- /dev/null +++ b/pkg/minikube/config/profile_test.go @@ -0,0 +1,72 @@ +/* +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 config + +import ( + "path/filepath" + "testing" +) + +func TestListProfiles(t *testing.T) { + miniDir, err := filepath.Abs("./testdata/.minikube") + if err != nil { + t.Errorf("error getting dir path for ./testdata/.minikube : %v", err) + } + // test cases for valid profiles + var testCasesValidProfs = []struct { + index int + expectName string + vmDriver string + }{ + {0, "p1", "hyperkit"}, + {1, "p2", "virtualbox"}, + } + + // test cases for invalid profiles + var testCasesInValidProfs = []struct { + index int + expectName string + vmDriver string + }{ + {0, "p3_empty", ""}, + {1, "p4_invalid_file", ""}, + {2, "p5_partial_config", ""}, + } + + val, inv, err := ListProfiles(miniDir) + + for _, tt := range testCasesValidProfs { + if val[tt.index].Name != tt.expectName { + t.Errorf("expected %s got %v", tt.expectName, val[tt.index].Name) + } + if val[tt.index].Config.MachineConfig.VMDriver != tt.vmDriver { + t.Errorf("expected %s got %v", tt.vmDriver, val[tt.index].Config.MachineConfig.VMDriver) + } + + } + + // making sure it returns the invalid profiles + for _, tt := range testCasesInValidProfs { + if inv[tt.index].Name != tt.expectName { + t.Errorf("expected %s got %v", tt.expectName, inv[tt.index].Name) + } + } + + if err != nil { + t.Errorf("error listing profiles %v", err) + } +} diff --git a/pkg/minikube/config/testdata/.minikube/config/invalid_config.json b/pkg/minikube/config/testdata/.minikube/config/invalid_config.json new file mode 100644 index 0000000000..2f98c2ecbe --- /dev/null +++ b/pkg/minikube/config/testdata/.minikube/config/invalid_config.json @@ -0,0 +1,2 @@ +{ + "vm-driver": "kvm2" diff --git a/pkg/minikube/config/testdata/.minikube/config/valid_config.json b/pkg/minikube/config/testdata/.minikube/config/valid_config.json new file mode 100644 index 0000000000..1ddbb4892a --- /dev/null +++ b/pkg/minikube/config/testdata/.minikube/config/valid_config.json @@ -0,0 +1,7 @@ +{ + "vm-driver": "kvm2", + "cpus": 4, + "disk-size": "20g", + "show-libmachine-logs": true, + "log_dir": "/etc/hosts" +} diff --git a/pkg/minikube/config/testdata/.minikube/profiles/p1/config.json b/pkg/minikube/config/testdata/.minikube/profiles/p1/config.json new file mode 100644 index 0000000000..86699a29bb --- /dev/null +++ b/pkg/minikube/config/testdata/.minikube/profiles/p1/config.json @@ -0,0 +1,50 @@ +{ + "MachineConfig": { + "KeepContext": false, + "MinikubeISO": "https://storage.googleapis.com/minikube/iso/minikube-v1.2.0.iso", + "Memory": 2000, + "CPUs": 2, + "DiskSize": 20000, + "VMDriver": "hyperkit", + "ContainerRuntime": "docker", + "HyperkitVpnKitSock": "", + "HyperkitVSockPorts": [], + "XhyveDiskDriver": "ahci-hd", + "DockerEnv": null, + "InsecureRegistry": null, + "RegistryMirror": null, + "HostOnlyCIDR": "192.168.99.1/24", + "HypervVirtualSwitch": "", + "KVMNetwork": "default", + "KVMQemuURI": "qemu:///system", + "KVMGPU": false, + "KVMHidden": false, + "DockerOpt": null, + "DisableDriverMounts": false, + "NFSShare": [], + "NFSSharesRoot": "/nfsshares", + "UUID": "", + "NoVTXCheck": false, + "DNSProxy": false, + "HostDNSResolver": true + }, + "KubernetesConfig": { + "KubernetesVersion": "v1.15.0", + "NodeIP": "192.168.64.75", + "NodePort": 8443, + "NodeName": "minikube", + "APIServerName": "minikubeCA", + "APIServerNames": null, + "APIServerIPs": null, + "DNSDomain": "cluster.local", + "ContainerRuntime": "docker", + "CRISocket": "", + "NetworkPlugin": "", + "FeatureGates": "", + "ServiceCIDR": "10.96.0.0/12", + "ImageRepository": "", + "ExtraOptions": null, + "ShouldLoadCachedImages": true, + "EnableDefaultCNI": false + } +} \ No newline at end of file diff --git a/pkg/minikube/config/testdata/.minikube/profiles/p2/config.json b/pkg/minikube/config/testdata/.minikube/profiles/p2/config.json new file mode 100644 index 0000000000..d77e0221d2 --- /dev/null +++ b/pkg/minikube/config/testdata/.minikube/profiles/p2/config.json @@ -0,0 +1,49 @@ +{ + "MachineConfig": { + "KeepContext": false, + "MinikubeISO": "https://storage.googleapis.com/minikube/iso/minikube-v1.2.0.iso", + "Memory": 2000, + "CPUs": 2, + "DiskSize": 20000, + "VMDriver": "virtualbox", + "ContainerRuntime": "docker", + "HyperkitVpnKitSock": "", + "HyperkitVSockPorts": [], + "DockerEnv": null, + "InsecureRegistry": null, + "RegistryMirror": null, + "HostOnlyCIDR": "192.168.99.1/24", + "HypervVirtualSwitch": "", + "KVMNetwork": "default", + "KVMQemuURI": "qemu:///system", + "KVMGPU": false, + "KVMHidden": false, + "DockerOpt": null, + "DisableDriverMounts": false, + "NFSShare": [], + "NFSSharesRoot": "/nfsshares", + "UUID": "", + "NoVTXCheck": false, + "DNSProxy": false, + "HostDNSResolver": true + }, + "KubernetesConfig": { + "KubernetesVersion": "v1.15.0", + "NodeIP": "192.168.99.136", + "NodePort": 8443, + "NodeName": "minikube", + "APIServerName": "minikubeCA", + "APIServerNames": null, + "APIServerIPs": null, + "DNSDomain": "cluster.local", + "ContainerRuntime": "docker", + "CRISocket": "", + "NetworkPlugin": "", + "FeatureGates": "", + "ServiceCIDR": "10.96.0.0/12", + "ImageRepository": "", + "ExtraOptions": null, + "ShouldLoadCachedImages": true, + "EnableDefaultCNI": false + } +} \ No newline at end of file diff --git a/pkg/minikube/config/testdata/.minikube/profiles/p3_empty/config.json b/pkg/minikube/config/testdata/.minikube/profiles/p3_empty/config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pkg/minikube/config/testdata/.minikube/profiles/p4_invalid_file/config.json b/pkg/minikube/config/testdata/.minikube/profiles/p4_invalid_file/config.json new file mode 100644 index 0000000000..9e2e347718 --- /dev/null +++ b/pkg/minikube/config/testdata/.minikube/profiles/p4_invalid_file/config.json @@ -0,0 +1 @@ +invalid json file :) \ No newline at end of file diff --git a/pkg/minikube/config/testdata/.minikube/profiles/p5_partial_config/config.json b/pkg/minikube/config/testdata/.minikube/profiles/p5_partial_config/config.json new file mode 100644 index 0000000000..29f62c0149 --- /dev/null +++ b/pkg/minikube/config/testdata/.minikube/profiles/p5_partial_config/config.json @@ -0,0 +1,47 @@ +{ + "MachineConfig": { + "KeepContext": false, + "MinikubeISO": "https://storage.googleapis.com/minikube/iso/minikube-v1.2.0.iso", + "Memory": 2000, + "CPUs": 2, + "DiskSize": 20000, + "ContainerRuntime": "docker", + "HyperkitVpnKitSock": "", + "HyperkitVSockPorts": [], + "XhyveDiskDriver": "ahci-hd", + "DockerEnv": null, + "InsecureRegistry": null, + "RegistryMirror": null, + "HostOnlyCIDR": "192.168.99.1/24", + "HypervVirtualSwitch": "", + "KVMNetwork": "default", + "KVMQemuURI": "qemu:///system", + "KVMGPU": false, + "KVMHidden": false, + "DockerOpt": null, + "DisableDriverMounts": false, + "NFSShare": [], + "NFSSharesRoot": "/nfsshares", + "UUID": "", + "NoVTXCheck": false, + "DNSProxy": false, + "HostDNSResolver": true + }, + "KubernetesConfig": { + "NodePort": 8443, + "NodeName": "minikube", + "APIServerName": "minikubeCA", + "APIServerNames": null, + "APIServerIPs": null, + "DNSDomain": "cluster.local", + "ContainerRuntime": "docker", + "CRISocket": "", + "NetworkPlugin": "", + "FeatureGates": "", + "ServiceCIDR": "10.96.0.0/12", + "ImageRepository": "", + "ExtraOptions": null, + "ShouldLoadCachedImages": true, + "EnableDefaultCNI": false + } +} \ No newline at end of file diff --git a/pkg/minikube/config/types.go b/pkg/minikube/config/types.go index 8566c1a20b..5716bb4c33 100644 --- a/pkg/minikube/config/types.go +++ b/pkg/minikube/config/types.go @@ -22,6 +22,12 @@ import ( "k8s.io/minikube/pkg/util" ) +// Profile represents a minikube profile +type Profile struct { + Name string + Config *Config +} + // Config contains machine and k8s config type Config struct { MachineConfig MachineConfig @@ -39,7 +45,6 @@ type MachineConfig struct { ContainerRuntime string HyperkitVpnKitSock string // Only used by the Hyperkit driver HyperkitVSockPorts []string // Only used by the Hyperkit driver - XhyveDiskDriver string // Only used by the xhyve driver DockerEnv []string // Each entry is formatted as KEY=VALUE. InsecureRegistry []string RegistryMirror []string @@ -51,7 +56,7 @@ type MachineConfig struct { 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 and xhyve + 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 d52f913115..98c62c8e6f 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -59,12 +59,12 @@ func ArchTag(hasTag bool) string { return "-" + runtime.GOARCH + ":" } +// DriverMock is a mock driver. +const DriverMock = "mock-driver" + // DriverNone is the none driver. const DriverNone = "none" -// DriverKvmOld is the depricated kvm driver option name -const DriverKvmOld = "kvm" - // DriverKvm2 is the kvm2 driver option name for in linux const DriverKvm2 = "kvm2" @@ -83,27 +83,9 @@ const DriverVmwareFusion = "vmwarefusion" // DriverHyperv is the hyperv driver option for windows const DriverHyperv = "hyperv" -// DriverXhyve is the depricated xhyve driver option name -const DriverXhyve = "xhyve" - // DriverParallels is the parallels driver option name const DriverParallels = "parallels" -// SupportedVMDrivers is a list of supported drivers on all platforms. Currently -// used in gendocs. -var SupportedVMDrivers = [...]string{ - DriverVirtualbox, - DriverParallels, - DriverVmwareFusion, - DriverKvmOld, - DriverXhyve, - DriverHyperv, - DriverHyperkit, - DriverKvm2, - DriverVmware, - DriverNone, -} - // DefaultMinipath is the default Minikube path (under the home directory) var DefaultMinipath = filepath.Join(homedir.HomeDir(), ".minikube") @@ -194,10 +176,10 @@ var DefaultISOURL = fmt.Sprintf("https://storage.googleapis.com/%s/minikube-%s.i var DefaultISOSHAURL = DefaultISOURL + SHASuffix // DefaultKubernetesVersion is the default kubernetes version -var DefaultKubernetesVersion = "v1.15.0" +var DefaultKubernetesVersion = "v1.15.1" // NewestKubernetesVersion is the newest Kubernetes version to test against -var NewestKubernetesVersion = "v1.15.0" +var NewestKubernetesVersion = "v1.15.1" // OldestKubernetesVersion is the oldest Kubernetes version to test against var OldestKubernetesVersion = "v1.10.13" @@ -209,13 +191,21 @@ var ConfigFilePath = MakeMiniPath("config") var ConfigFile = MakeMiniPath("config", "config.json") // GetProfileFile returns the Minikube profile config file -func GetProfileFile(profile string) string { - return filepath.Join(GetMinipath(), "profiles", profile, "config.json") +func GetProfileFile(profile string, miniHome ...string) string { + miniPath := GetMinipath() + if len(miniHome) > 0 { + miniPath = miniHome[0] + } + return filepath.Join(miniPath, "profiles", profile, "config.json") } // GetProfilePath returns the Minikube profile path of config file -func GetProfilePath(profile string) string { - return filepath.Join(GetMinipath(), "profiles", profile) +func GetProfilePath(profile string, miniHome ...string) string { + miniPath := GetMinipath() + if len(miniHome) > 0 { + miniPath = miniHome[0] + } + return filepath.Join(miniPath, "profiles", profile) } // AddonsPath is the default path of the addons configuration @@ -435,6 +425,6 @@ const ( ) const ( - // KVMDocumentation the documentation of the KVM driver - KVMDocumentation = "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver" + // DriverDocumentation the documentation of the KVM driver + DriverDocumentation = "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md" ) diff --git a/pkg/minikube/constants/constants_darwin.go b/pkg/minikube/constants/constants_darwin.go index 081ffea3fe..707f5f9925 100644 --- a/pkg/minikube/constants/constants_darwin.go +++ b/pkg/minikube/constants/constants_darwin.go @@ -1,4 +1,4 @@ -// +build darwin +// +build darwin, !gendocs /* Copyright 2016 The Kubernetes Authors All rights reserved. @@ -19,3 +19,12 @@ limitations under the License. package constants var DefaultMountDir = "/Users" + +// SupportedVMDrivers is a list of supported drivers on Darwin. +var SupportedVMDrivers = [...]string{ + DriverVirtualbox, + DriverParallels, + DriverVmwareFusion, + DriverHyperkit, + DriverVmware, +} diff --git a/pkg/minikube/drivers/xhyve/doc.go b/pkg/minikube/constants/constants_gendocs.go similarity index 58% rename from pkg/minikube/drivers/xhyve/doc.go rename to pkg/minikube/constants/constants_gendocs.go index 1d8c8b5ae3..19eceaf26b 100644 --- a/pkg/minikube/drivers/xhyve/doc.go +++ b/pkg/minikube/constants/constants_gendocs.go @@ -1,5 +1,7 @@ +// +build gendocs + /* -Copyright 2018 The Kubernetes Authors All rights reserved. +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. @@ -14,4 +16,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -package xhyve +package constants + +var DefaultMountDir = "$HOME" + +// SupportedVMDrivers is a list of supported drivers on all platforms. +var SupportedVMDrivers = [...]string{ + DriverVirtualbox, + DriverParallels, + DriverVmwareFusion, + DriverHyperv, + DriverHyperkit, + DriverKvm2, + DriverVmware, + DriverNone, +} diff --git a/pkg/minikube/constants/constants_linux.go b/pkg/minikube/constants/constants_linux.go index a5419b7771..0fa300617f 100644 --- a/pkg/minikube/constants/constants_linux.go +++ b/pkg/minikube/constants/constants_linux.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux, !gendocs /* Copyright 2016 The Kubernetes Authors All rights reserved. @@ -24,3 +24,13 @@ import ( // DefaultMountDir is the default mount dir var DefaultMountDir = homedir.HomeDir() + +// SupportedVMDrivers is a list of supported drivers on Linux. +var SupportedVMDrivers = [...]string{ + DriverVirtualbox, + DriverParallels, + DriverVmwareFusion, + DriverKvm2, + DriverVmware, + DriverNone, +} diff --git a/pkg/minikube/constants/constants_windows.go b/pkg/minikube/constants/constants_windows.go index aa66af22a6..fb0139964a 100644 --- a/pkg/minikube/constants/constants_windows.go +++ b/pkg/minikube/constants/constants_windows.go @@ -1,4 +1,4 @@ -// +build windows +// +build windows, !gendocs /* Copyright 2016 The Kubernetes Authors All rights reserved. @@ -23,3 +23,11 @@ import ( ) var DefaultMountDir = homedir.HomeDir() + +// SupportedVMDrivers is a list of supported drivers on Windows. +var SupportedVMDrivers = [...]string{ + DriverVirtualbox, + DriverVmwareFusion, + DriverHyperv, + DriverVmware, +} diff --git a/pkg/minikube/cruntime/containerd.go b/pkg/minikube/cruntime/containerd.go index 20ec4e27da..88ed475be1 100644 --- a/pkg/minikube/cruntime/containerd.go +++ b/pkg/minikube/cruntime/containerd.go @@ -21,7 +21,7 @@ import ( "strings" "github.com/golang/glog" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" ) // Containerd contains containerd runtime state @@ -36,8 +36,8 @@ func (r *Containerd) Name() string { } // Style is the console style for containerd -func (r *Containerd) Style() console.StyleEnum { - return console.Containerd +func (r *Containerd) Style() out.StyleEnum { + return out.Containerd } // Version retrieves the current version of this runtime @@ -136,3 +136,8 @@ func (r *Containerd) StopContainers(ids []string) error { func (r *Containerd) ContainerLogCmd(id string, len int, follow bool) string { return criContainerLogCmd(id, len, follow) } + +// SystemLogCmd returns the command to retrieve system logs +func (r *Containerd) SystemLogCmd(len int) string { + return fmt.Sprintf("sudo journalctl -u containerd -n %d", len) +} diff --git a/pkg/minikube/cruntime/crio.go b/pkg/minikube/cruntime/crio.go index 67b86fac18..4c9a8bb192 100644 --- a/pkg/minikube/cruntime/crio.go +++ b/pkg/minikube/cruntime/crio.go @@ -21,7 +21,7 @@ import ( "strings" "github.com/golang/glog" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" ) // CRIO contains CRIO runtime state @@ -36,8 +36,8 @@ func (r *CRIO) Name() string { } // Style is the console style for CRIO -func (r *CRIO) Style() console.StyleEnum { - return console.CRIO +func (r *CRIO) Style() out.StyleEnum { + return out.CRIO } // Version retrieves the current version of this runtime @@ -133,3 +133,8 @@ func (r *CRIO) StopContainers(ids []string) error { func (r *CRIO) ContainerLogCmd(id string, len int, follow bool) string { return criContainerLogCmd(id, len, follow) } + +// SystemLogCmd returns the command to retrieve system logs +func (r *CRIO) SystemLogCmd(len int) string { + return fmt.Sprintf("sudo journalctl -u crio -n %d", len) +} diff --git a/pkg/minikube/cruntime/cruntime.go b/pkg/minikube/cruntime/cruntime.go index 2cb9310532..b7b74e1310 100644 --- a/pkg/minikube/cruntime/cruntime.go +++ b/pkg/minikube/cruntime/cruntime.go @@ -22,7 +22,7 @@ import ( "github.com/golang/glog" "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" ) // CommandRunner is the subset of command.Runner this package consumes @@ -46,7 +46,7 @@ type Manager interface { // Available returns an error if it is not possible to use this runtime on a host Available() error // Style is an associated StyleEnum for Name() - Style() console.StyleEnum + Style() out.StyleEnum // KubeletOptions returns kubelet options for a runtime. KubeletOptions() map[string]string @@ -66,6 +66,8 @@ type Manager interface { StopContainers([]string) error // ContainerLogCmd returns the command to retrieve the log for a container based on ID ContainerLogCmd(string, int, bool) string + // SystemLogCmd returns the command to return the system logs + SystemLogCmd(int) string } // Config is runtime configuration diff --git a/pkg/minikube/cruntime/docker.go b/pkg/minikube/cruntime/docker.go index c97368ac03..817049aff1 100644 --- a/pkg/minikube/cruntime/docker.go +++ b/pkg/minikube/cruntime/docker.go @@ -22,7 +22,7 @@ import ( "strings" "github.com/golang/glog" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" ) // KubernetesContainerPrefix is the prefix of each kubernetes container @@ -40,8 +40,8 @@ func (r *Docker) Name() string { } // Style is the console style for Docker -func (r *Docker) Style() console.StyleEnum { - return console.Docker +func (r *Docker) Style() out.StyleEnum { + return out.Docker } // Version retrieves the current version of this runtime @@ -153,3 +153,8 @@ func (r *Docker) ContainerLogCmd(id string, len int, follow bool) string { cmd.WriteString(id) return cmd.String() } + +// SystemLogCmd returns the command to retrieve system logs +func (r *Docker) SystemLogCmd(len int) string { + return fmt.Sprintf("sudo journalctl -u docker -n %d", len) +} diff --git a/pkg/minikube/drivers/kvm/driver.go b/pkg/minikube/drivers/kvm/driver.go deleted file mode 100644 index 451712b4c7..0000000000 --- a/pkg/minikube/drivers/kvm/driver.go +++ /dev/null @@ -1,76 +0,0 @@ -// +build linux - -/* -Copyright 2018 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 kvm - -import ( - "fmt" - "path/filepath" - - "github.com/docker/machine/libmachine/drivers" - cfg "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/constants" - "k8s.io/minikube/pkg/minikube/registry" -) - -func init() { - if err := registry.Register(registry.DriverDef{ - Name: constants.DriverKvmOld, - Builtin: false, - ConfigCreator: createKVMHost, - }); err != nil { - panic(fmt.Sprintf("register: %v", err)) - } -} - -// Delete this once the following PR is merged: -// https://github.com/dhiltgen/docker-machine-kvm/pull/68 -type kvmDriver struct { - *drivers.BaseDriver - - Memory int - DiskSize int - CPU int - Network string - PrivateNetwork string - ISO string - Boot2DockerURL string - DiskPath string - CacheMode string - IOMode string -} - -func createKVMHost(config cfg.MachineConfig) interface{} { - return &kvmDriver{ - BaseDriver: &drivers.BaseDriver{ - MachineName: cfg.GetMachineName(), - StorePath: constants.GetMinipath(), - SSHUser: "docker", - }, - Memory: config.Memory, - CPU: config.CPUs, - Network: config.KVMNetwork, - PrivateNetwork: "docker-machines", - Boot2DockerURL: config.Downloader.GetISOFileURI(config.MinikubeISO), - DiskSize: config.DiskSize, - DiskPath: filepath.Join(constants.GetMinipath(), "machines", cfg.GetMachineName(), fmt.Sprintf("%s.rawdisk", cfg.GetMachineName())), - ISO: filepath.Join(constants.GetMinipath(), "machines", cfg.GetMachineName(), "boot2docker.iso"), - CacheMode: "default", - IOMode: "threads", - } -} diff --git a/pkg/minikube/drivers/xhyve/driver.go b/pkg/minikube/drivers/xhyve/driver.go deleted file mode 100644 index 3fc0ae21fb..0000000000 --- a/pkg/minikube/drivers/xhyve/driver.go +++ /dev/null @@ -1,88 +0,0 @@ -// +build darwin - -/* -Copyright 2018 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 xhyve - -import ( - "fmt" - "os" - - "github.com/docker/machine/libmachine/drivers" - cfg "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/constants" - "k8s.io/minikube/pkg/minikube/registry" -) - -const errMsg = ` -The Xhyve driver is not included in minikube yet. Please follow the directions at -https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#xhyve-driver -` - -func init() { - if err := registry.Register(registry.DriverDef{ - Name: constants.DriverXhyve, - Builtin: false, - ConfigCreator: createXhyveHost, - DriverCreator: func() drivers.Driver { - fmt.Fprintln(os.Stderr, errMsg) - os.Exit(1) - return nil - }, - }); err != nil { - panic(fmt.Sprintf("register: %v", err)) - } -} - -type xhyveDriver struct { - *drivers.BaseDriver - - Boot2DockerURL string - BootCmd string - CPU int - CaCertPath string - DiskSize int64 - MacAddr string - Memory int - PrivateKeyPath string - UUID string - NFSShare bool - DiskNumber int - Virtio9p bool - Virtio9pFolder string - QCow2 bool - RawDisk bool -} - -func createXhyveHost(config cfg.MachineConfig) interface{} { - useVirtio9p := !config.DisableDriverMounts - return &xhyveDriver{ - BaseDriver: &drivers.BaseDriver{ - MachineName: cfg.GetMachineName(), - StorePath: constants.GetMinipath(), - }, - Memory: config.Memory, - CPU: config.CPUs, - Boot2DockerURL: config.Downloader.GetISOFileURI(config.MinikubeISO), - BootCmd: "loglevel=3 user=docker console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 systemd.legacy_systemd_cgroup_controller=yes base host=" + cfg.GetMachineName(), - DiskSize: int64(config.DiskSize), - Virtio9p: useVirtio9p, - Virtio9pFolder: "/Users", - QCow2: false, - RawDisk: config.XhyveDiskDriver == "virtio-blk", - } -} diff --git a/pkg/minikube/exit/exit.go b/pkg/minikube/exit/exit.go index b92367f381..efe606ddd8 100644 --- a/pkg/minikube/exit/exit.go +++ b/pkg/minikube/exit/exit.go @@ -23,8 +23,9 @@ import ( "runtime" "github.com/golang/glog" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/problem" + "k8s.io/minikube/pkg/minikube/translate" ) // Exit codes based on sysexits(3) @@ -44,17 +45,15 @@ const ( MaxLogEntries = 3 ) -// Usage outputs a usage error and exits with error code 64 -func Usage(format string, a ...interface{}) { - console.ErrStyle(console.Usage, format, a...) +// UsageT outputs a templated usage error and exits with error code 64 +func UsageT(format string, a ...out.V) { + out.ErrT(out.Usage, format, a...) os.Exit(BadUsage) } -// WithCode outputs a fatal error message and exits with a supplied error code. -func WithCode(code int, format string, a ...interface{}) { - // use Warning because Error will display a duplicate message to stderr - glog.Warningf(format, a...) - console.Fatal(format, a...) +// WithCodeT outputs a templated fatal error message and exits with the supplied error code. +func WithCodeT(code int, format string, a ...out.V) { + out.FatalT(format, a...) os.Exit(code) } @@ -70,12 +69,12 @@ func WithError(msg string, err error) { // WithProblem outputs info related to a known problem and exits. func WithProblem(msg string, p *problem.Problem) { - console.Err("\n") - console.Fatal(msg) + out.ErrT(out.Empty, "") + out.FatalT(msg) p.Display() - console.Err("\n") - console.ErrStyle(console.Sad, "If the above advice does not help, please let us know: ") - console.ErrStyle(console.URL, "https://github.com/kubernetes/minikube/issues/new") + out.ErrT(out.Empty, "") + out.ErrT(out.Sad, "If the above advice does not help, please let us know: ") + out.ErrT(out.URL, "https://github.com/kubernetes/minikube/issues/new/choose") os.Exit(Config) } @@ -84,12 +83,12 @@ func WithLogEntries(msg string, err error, entries map[string][]string) { displayError(msg, err) for name, lines := range entries { - console.OutStyle(console.FailureType, "Problems detected in %q:", name) + out.T(out.FailureType, "Problems detected in {{.entry}}:", out.V{"entry": name}) if len(lines) > MaxLogEntries { lines = lines[:MaxLogEntries] } for _, l := range lines { - console.OutStyle(console.LogEntry, l) + out.T(out.LogEntry, l) } } os.Exit(Software) @@ -98,9 +97,9 @@ func WithLogEntries(msg string, err error, entries map[string][]string) { func displayError(msg string, err error) { // use Warning because Error will display a duplicate message to stderr glog.Warningf(fmt.Sprintf("%s: %v", msg, err)) - console.Err("\n") - console.Fatal("%s: %v", msg, err) - console.Err("\n") - console.ErrStyle(console.Sad, "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:") - console.ErrStyle(console.URL, "https://github.com/kubernetes/minikube/issues/new") + out.ErrT(out.Empty, "") + out.FatalT("{{.msg}}: {{.err}}", out.V{"msg": translate.T(msg), "err": err}) + out.ErrT(out.Empty, "") + out.ErrT(out.Sad, "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:") + out.ErrT(out.URL, "https://github.com/kubernetes/minikube/issues/new/choose") } diff --git a/pkg/minikube/extract/extract.go b/pkg/minikube/extract/extract.go index 58210d6b71..b8b1b806f2 100644 --- a/pkg/minikube/extract/extract.go +++ b/pkg/minikube/extract/extract.go @@ -47,6 +47,9 @@ var blacklist = []string{ "opt %s", } +// ErrMapFile is a constant to refer to the err_map file, which contains the Advice strings. +const ErrMapFile string = "pkg/minikube/problem/err_map.go" + // state is a struct that represent the current state of the extraction process type state struct { // The list of functions to check for @@ -112,16 +115,6 @@ func setParentFunc(e *state, f string) { // TranslatableStrings finds all strings to that need to be translated in paths and prints them out to all json files in output func TranslatableStrings(paths []string, functions []string, output string) error { - cwd, err := os.Getwd() - if err != nil { - return errors.Wrap(err, "Getting current working directory") - } - - if strings.Contains(cwd, "cmd") { - fmt.Println("Run extract.go from the minikube root directory.") - os.Exit(1) - } - e, err := newExtractor(functions) if err != nil { @@ -173,6 +166,10 @@ func inspectFile(e *state) error { return err } + if e.filename == ErrMapFile { + return extractAdvice(file, e) + } + ast.Inspect(file, func(x ast.Node) bool { if fi, ok := x.(*ast.File); ok { e.currentPackage = fi.Name.String() @@ -394,3 +391,30 @@ func addParentFuncToList(e *state) { e.fs.Push(e.parentFunc) } } + +// extractAdvice specifically extracts Advice strings in err_map.go, since they don't conform to our normal translatable string format. +func extractAdvice(f ast.Node, e *state) error { + ast.Inspect(f, func(x ast.Node) bool { + // We want the "Advice: " key-value pair + // First make sure we're looking at a kvp + kvp, ok := x.(*ast.KeyValueExpr) + if !ok { + return true + } + + // Now make sure we're looking at an Advice kvp + i, ok := kvp.Key.(*ast.Ident) + if !ok { + return true + } + + if i.Name == "Advice" { + // At this point we know the value in the kvp is guaranteed to be a string + advice, _ := kvp.Value.(*ast.BasicLit) + addStringToList(advice.Value, e) + } + return true + }) + + return nil +} diff --git a/pkg/minikube/extract/testdata/test.json b/pkg/minikube/extract/testdata/test.json index c7a3cf31ed..401e6db3eb 100644 --- a/pkg/minikube/extract/testdata/test.json +++ b/pkg/minikube/extract/testdata/test.json @@ -1,4 +1,7 @@ { + "Hint: This is not a URL, come on.": "", "Holy cow I'm in a loop!": "Something else", - "This was a choice: %s": "Something" + "This is a variable with a string assigned": "", + "This was a choice: %s": "Something", + "Wow another string: %s": "" } \ No newline at end of file diff --git a/pkg/minikube/logs/logs.go b/pkg/minikube/logs/logs.go index 2fe67514c2..6af57a34d4 100644 --- a/pkg/minikube/logs/logs.go +++ b/pkg/minikube/logs/logs.go @@ -29,8 +29,8 @@ import ( "github.com/golang/glog" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/cruntime" + "k8s.io/minikube/pkg/minikube/out" ) // rootCauseRe is a regular expression that matches known failure root causes @@ -100,12 +100,12 @@ func FindProblems(r cruntime.Manager, bs bootstrapper.Bootstrapper, runner comma // OutputProblems outputs discovered problems. func OutputProblems(problems map[string][]string, maxLines int) { for name, lines := range problems { - console.OutStyle(console.FailureType, "Problems detected in %q:", name) + out.T(out.FailureType, "Problems detected in {{.name}}:", out.V{"name": name}) if len(lines) > maxLines { lines = lines[len(lines)-maxLines:] } for _, l := range lines { - console.OutStyle(console.LogEntry, l) + out.T(out.LogEntry, l) } } } @@ -113,23 +113,22 @@ func OutputProblems(problems map[string][]string, maxLines int) { // Output displays logs from multiple sources in tail(1) format func Output(r cruntime.Manager, bs bootstrapper.Bootstrapper, runner command.Runner, lines int) error { cmds := logCommands(r, bs, lines, false) - - // These are not technically logs, but are useful to have in bug reports. - cmds["kernel"] = "uptime && uname -a" + cmds["kernel"] = "uptime && uname -a && grep PRETTY /etc/os-release" names := []string{} for k := range cmds { names = append(names, k) } - sort.Strings(names) + sort.Strings(names) failed := []string{} for i, name := range names { if i > 0 { - console.OutLn("") + out.T(out.Empty, "") } - console.OutLn("==> %s <==", name) + out.T(out.Empty, "==> {{.name}} <==", out.V{"name": name}) var b bytes.Buffer + err := runner.CombinedOutputTo(cmds[name], &b) if err != nil { glog.Errorf("failed: %v", err) @@ -138,9 +137,10 @@ func Output(r cruntime.Manager, bs bootstrapper.Bootstrapper, runner command.Run } scanner := bufio.NewScanner(&b) for scanner.Scan() { - console.OutLn(scanner.Text()) + out.T(out.Empty, scanner.Text()) } } + if len(failed) > 0 { return fmt.Errorf("unable to fetch logs for: %s", strings.Join(failed, ", ")) } @@ -163,5 +163,9 @@ func logCommands(r cruntime.Manager, bs bootstrapper.Bootstrapper, length int, f } cmds[pod] = r.ContainerLogCmd(ids[0], length, follow) } + cmds[r.Name()] = r.SystemLogCmd(length) + // Works across container runtimes with good formatting + // Fallback to 'docker ps' if it fails (none driver) + cmds["container status"] = "sudo crictl ps -a || sudo docker ps -a" return cmds } diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index e665f33501..a31cde810a 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -29,8 +29,8 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/out" ) // CacheBinariesForBootstrapper will cache binaries for a bootstrapper @@ -39,7 +39,7 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er var g errgroup.Group for _, bin := range binaries { - bin := bin + bin := bin // https://golang.org/doc/faq#closures_and_goroutines g.Go(func() error { if _, err := CacheBinary(bin, version, "linux", runtime.GOARCH); err != nil { return errors.Wrapf(err, "caching image %s", bin) @@ -78,7 +78,7 @@ func CacheBinary(binary, version, osName, archName string) (string, error) { options.Checksum = constants.GetKubernetesReleaseURLSHA1(binary, version, osName, archName) options.ChecksumHash = crypto.SHA1 - console.OutStyle(console.FileDownload, "Downloading %s %s", binary, version) + 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, "Error downloading %s %s", binary, version) } diff --git a/pkg/minikube/machine/client.go b/pkg/minikube/machine/client.go index c622bafe5e..458dbf9edb 100644 --- a/pkg/minikube/machine/client.go +++ b/pkg/minikube/machine/client.go @@ -43,6 +43,7 @@ import ( "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/registry" "k8s.io/minikube/pkg/minikube/sshutil" "k8s.io/minikube/pkg/provision" @@ -146,6 +147,9 @@ func (api *LocalClient) Close() error { // CommandRunner returns best available command runner for this host func CommandRunner(h *host.Host) (command.Runner, error) { + if h.DriverName == constants.DriverMock { + return &command.FakeCommandRunner{}, nil + } if h.DriverName == constants.DriverNone { return &command.ExecRunner{}, nil } @@ -269,7 +273,7 @@ func registerDriver(driverName string) { def, err := registry.Driver(driverName) if err != nil { if err == registry.ErrDriverNotFound { - exit.Usage("unsupported driver: %s", driverName) + exit.UsageT("unsupported driver: {{.name}}", out.V{"name": driverName}) } exit.WithError("error getting driver", err) } diff --git a/pkg/minikube/notify/notify.go b/pkg/minikube/notify/notify.go index d657786d60..557c364301 100644 --- a/pkg/minikube/notify/notify.go +++ b/pkg/minikube/notify/notify.go @@ -30,8 +30,8 @@ import ( "github.com/pkg/errors" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/version" ) @@ -66,13 +66,9 @@ func MaybePrintUpdateText(url string, lastUpdatePath string) { if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil { glog.Errorf("write time failed: %v", err) } - console.ErrStyle(console.WarningType, `There is a newer version of minikube available (%s%s). Download it here: -%s%s - -To disable this notification, run the following: -minikube config set WantUpdateNotification false -`, - version.VersionPrefix, latestVersion, updateLinkPrefix, latestVersion) + url := fmt.Sprintf("%s/%s", updateLinkPrefix, latestVersion) + out.ErrT(out.WarningType, `minikube {{.version}} is available! Download it: {{.url}}`, out.V{"version": latestVersion, "url": url}) + out.T(out.Tip, "To disable this notice, run: 'minikube config set WantUpdateNotification false'") } } diff --git a/pkg/minikube/notify/notify_test.go b/pkg/minikube/notify/notify_test.go index e78f6bf7b3..c87c2de372 100644 --- a/pkg/minikube/notify/notify_test.go +++ b/pkg/minikube/notify/notify_test.go @@ -29,7 +29,7 @@ import ( "github.com/blang/semver" "github.com/spf13/viper" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/tests" "k8s.io/minikube/pkg/version" ) @@ -151,7 +151,7 @@ func TestMaybePrintUpdateText(t *testing.T) { viper.Set(config.ReminderWaitPeriodInHours, 24) outputBuffer := tests.NewFakeFile() - console.SetErrFile(outputBuffer) + out.SetErrFile(outputBuffer) lastUpdateCheckFilePath := filepath.Join(tempDir, "last_update_check") // test that no update text is printed if the latest version is lower/equal to the current version diff --git a/pkg/minikube/console/console.go b/pkg/minikube/out/out.go similarity index 66% rename from pkg/minikube/console/console.go rename to pkg/minikube/out/out.go index 0e2389025f..d053a803df 100644 --- a/pkg/minikube/console/console.go +++ b/pkg/minikube/out/out.go @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package console provides a mechanism for sending localized, stylized output to the console. -package console +// Package out provides a mechanism for sending localized, stylized output to the console. +package out import ( "fmt" @@ -31,12 +31,12 @@ import ( // By design, this package uses global references to language and output objects, in preference // to passing a console object throughout the code base. Typical usage is: // -// console.SetOutFile(os.Stdout) -// console.Out("Starting up!") -// console.OutStyle(console.StatusChange, "Configuring things") +// out.SetOutFile(os.Stdout) +// out.String("Starting up!") +// out.T(out.StatusChange, "Configuring things") -// console.SetErrFile(os.Stderr) -// console.Fatal("Oh no, everything failed.") +// out.SetErrFile(os.Stderr) +// out.Fatal("Oh no, everything failed.") // NOTE: If you do not want colorized output, set MINIKUBE_IN_STYLE=false in your environment. @@ -57,23 +57,17 @@ type fdWriter interface { Fd() uintptr } -// Arg is a convenience wrapper for templating -type Arg map[string]interface{} +// V is a convenience wrapper for templating, it represents the variable key/value pair. +type V map[string]interface{} -// OutStyle writes a stylized and formatted message to stdout -func OutStyle(style StyleEnum, format string, a ...interface{}) { - outStyled := applyStyle(style, useColor, format) - Out(outStyled, a...) +// T writes a stylized and templated message to stdout +func T(style StyleEnum, format string, a ...V) { + outStyled := applyTemplateFormatting(style, useColor, format, a...) + String(outStyled) } -// OutT writes a stylized and templated message to stdout -func OutT(style StyleEnum, format string, a map[string]interface{}) { - outStyled := applyTemplateFormatting(style, useColor, format, a) - Out(outStyled) -} - -// Out writes a basic formatted string to stdout -func Out(format string, a ...interface{}) { +// String writes a basic formatted string to stdout +func String(format string, a ...interface{}) { if outFile == nil { glog.Warningf("[unset outFile]: %s", fmt.Sprintf(format, a...)) return @@ -84,20 +78,14 @@ func Out(format string, a ...interface{}) { } } -// OutLn writes a basic formatted string with a newline to stdout -func OutLn(format string, a ...interface{}) { - Out(format+"\n", a...) -} - -// ErrStyle writes a stylized and formatted error message to stderr -func ErrStyle(style StyleEnum, format string, a ...interface{}) { - errStyled := applyStyle(style, useColor, format) - Err(errStyled, a...) +// Ln writes a basic formatted string with a newline to stdout +func Ln(format string, a ...interface{}) { + String(format+"\n", a...) } // ErrT writes a stylized and templated error message to stderr -func ErrT(style StyleEnum, format string, a map[string]interface{}) { - errStyled := applyTemplateFormatting(style, useColor, format, a) +func ErrT(style StyleEnum, format string, a ...V) { + errStyled := applyTemplateFormatting(style, useColor, format, a...) Err(errStyled) } @@ -118,24 +106,24 @@ func ErrLn(format string, a ...interface{}) { Err(format+"\n", a...) } -// Success is a shortcut for writing a styled success message to stdout -func Success(format string, a ...interface{}) { - OutStyle(SuccessType, format, a...) +// SuccessT is a shortcut for writing a templated success message to stdout +func SuccessT(format string, a ...V) { + T(SuccessType, format, a...) } -// Fatal is a shortcut for writing a styled fatal message to stderr -func Fatal(format string, a ...interface{}) { - ErrStyle(FatalType, format, a...) +// FatalT is a shortcut for writing a templated fatal message to stderr +func FatalT(format string, a ...V) { + ErrT(FatalType, format, a...) } -// Warning is a shortcut for writing a styled warning message to stderr -func Warning(format string, a ...interface{}) { - ErrStyle(WarningType, format, a...) +// WarningT is a shortcut for writing a templated warning message to stderr +func WarningT(format string, a ...V) { + ErrT(WarningType, format, a...) } -// Failure is a shortcut for writing a styled failure message to stderr -func Failure(format string, a ...interface{}) { - ErrStyle(FailureType, format, a...) +// FailureT is a shortcut for writing a templated failure message to stderr +func FailureT(format string, a ...V) { + ErrT(FailureType, format, a...) } // SetOutFile configures which writer standard output goes to. diff --git a/pkg/minikube/console/console_test.go b/pkg/minikube/out/out_test.go similarity index 51% rename from pkg/minikube/console/console_test.go rename to pkg/minikube/out/out_test.go index 7eb1759bda..79646c5de4 100644 --- a/pkg/minikube/console/console_test.go +++ b/pkg/minikube/out/out_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package console +package out import ( "fmt" @@ -26,52 +26,6 @@ import ( "k8s.io/minikube/pkg/minikube/translate" ) -func TestOutStyle(t *testing.T) { - // Set the system locale to Arabic and define a dummy translation file. - if err := translate.SetPreferredLanguage("ar"); err != nil { - t.Fatalf("SetPreferredLanguage: %v", err) - } - translate.Translations = map[string]interface{}{ - "Installing Kubernetes version %s ...": "... %s تثبيت Kubernetes الإصدار", - } - - var testCases = []struct { - style StyleEnum - message string - params []interface{} - want string - wantASCII string - }{ - {Happy, "Happy", nil, "😄 Happy\n", "* Happy\n"}, - {Option, "Option", nil, " ▪ Option\n", " - Option\n"}, - {WarningType, "Warning", nil, "⚠️ Warning\n", "! Warning\n"}, - {FatalType, "Fatal: %v", []interface{}{"ugh"}, "💣 Fatal: ugh\n", "X Fatal: ugh\n"}, - {WaitingPods, "wait", nil, "⌛ wait", "* wait"}, - {Issue, "http://i/%d", []interface{}{10000}, " ▪ http://i/10000\n", " - http://i/10000\n"}, - {Usage, "raw: %s %s", []interface{}{"'%'", "%d"}, "💡 raw: '%' %d\n", "* raw: '%' %d\n"}, - {Running, "Installing Kubernetes version %s ...", []interface{}{"v1.13"}, "🏃 ... v1.13 تثبيت Kubernetes الإصدار\n", "* ... v1.13 تثبيت Kubernetes الإصدار\n"}, - } - for _, tc := range testCases { - for _, override := range []bool{true, false} { - t.Run(fmt.Sprintf("%s-override-%v", tc.message, override), func(t *testing.T) { - // Set MINIKUBE_IN_STYLE= - os.Setenv(OverrideEnv, strconv.FormatBool(override)) - f := tests.NewFakeFile() - SetOutFile(f) - OutStyle(tc.style, tc.message, tc.params...) - got := f.String() - want := tc.wantASCII - if override { - want = tc.want - } - if got != want { - t.Errorf("OutStyle() = %q (%d runes), want %q (%d runes)", got, len(got), want, len(want)) - } - }) - } - } -} - func TestOutT(t *testing.T) { // Set the system locale to Arabic and define a dummy translation file. if err := translate.SetPreferredLanguage("ar"); err != nil { @@ -84,18 +38,18 @@ func TestOutT(t *testing.T) { var testCases = []struct { style StyleEnum message string - params Arg + params V want string wantASCII string }{ {Happy, "Happy", nil, "😄 Happy\n", "* Happy\n"}, {Option, "Option", nil, " ▪ Option\n", " - Option\n"}, {WarningType, "Warning", nil, "⚠️ Warning\n", "! Warning\n"}, - {FatalType, "Fatal: {{.error}}", Arg{"error": "ugh"}, "💣 Fatal: ugh\n", "X Fatal: ugh\n"}, + {FatalType, "Fatal: {{.error}}", V{"error": "ugh"}, "💣 Fatal: ugh\n", "X Fatal: ugh\n"}, {WaitingPods, "wait", nil, "⌛ wait", "* wait"}, - {Issue, "http://i/{{.number}}", Arg{"number": 10000}, " ▪ http://i/10000\n", " - http://i/10000\n"}, - {Usage, "raw: {{.one}} {{.two}}", Arg{"one": "'%'", "two": "%d"}, "💡 raw: '%' %d\n", "* raw: '%' %d\n"}, - {Running, "Installing Kubernetes version {{.version}} ...", Arg{"version": "v1.13"}, "🏃 ... v1.13 تثبيت Kubernetes الإصدار\n", "* ... v1.13 تثبيت Kubernetes الإصدار\n"}, + {Issue, "http://i/{{.number}}", V{"number": 10000}, " ▪ http://i/10000\n", " - http://i/10000\n"}, + {Usage, "raw: {{.one}} {{.two}}", V{"one": "'%'", "two": "%d"}, "💡 raw: '%' %d\n", "* raw: '%' %d\n"}, + {Running, "Installing Kubernetes version {{.version}} ...", V{"version": "v1.13"}, "🏃 ... v1.13 تثبيت Kubernetes الإصدار\n", "* ... v1.13 تثبيت Kubernetes الإصدار\n"}, } for _, tc := range testCases { for _, override := range []bool{true, false} { @@ -104,7 +58,7 @@ func TestOutT(t *testing.T) { os.Setenv(OverrideEnv, strconv.FormatBool(override)) f := tests.NewFakeFile() SetOutFile(f) - OutT(tc.style, tc.message, tc.params) + T(tc.style, tc.message, tc.params) got := f.String() want := tc.wantASCII if override { @@ -136,9 +90,9 @@ func TestOut(t *testing.T) { SetOutFile(f) ErrLn("unrelated message") if tc.arg == nil { - Out(tc.format) + String(tc.format) } else { - Out(tc.format, tc.arg) + String(tc.format, tc.arg) } got := f.String() if got != tc.want { @@ -153,7 +107,7 @@ func TestErr(t *testing.T) { f := tests.NewFakeFile() SetErrFile(f) Err("xyz123 %s\n", "%s%%%d") - OutLn("unrelated message") + Ln("unrelated message") got := f.String() want := "xyz123 %s%%%d\n" @@ -161,15 +115,3 @@ func TestErr(t *testing.T) { t.Errorf("Err() = %q, want %q", got, want) } } - -func TestErrStyle(t *testing.T) { - os.Setenv(OverrideEnv, "1") - f := tests.NewFakeFile() - SetErrFile(f) - ErrStyle(FatalType, "error: %s", "%s%%%d") - got := f.String() - want := "💣 error: %s%%%d\n" - if got != want { - t.Errorf("ErrStyle() = %q, want %q", got, want) - } -} diff --git a/pkg/minikube/console/style.go b/pkg/minikube/out/style.go similarity index 93% rename from pkg/minikube/console/style.go rename to pkg/minikube/out/style.go index c86c4fe055..564abd8fad 100644 --- a/pkg/minikube/console/style.go +++ b/pkg/minikube/out/style.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package console +package out import ( "bytes" @@ -49,6 +49,7 @@ type style struct { // styles is a map of style name to style struct // For consistency, ensure that emojis added render with the same width across platforms. var styles = map[StyleEnum]style{ + Empty: {Prefix: "", LowPrefix: ""}, Happy: {Prefix: "😄 "}, SuccessType: {Prefix: "✅ "}, FailureType: {Prefix: "❌ "}, @@ -78,6 +79,7 @@ var styles = map[StyleEnum]style{ Issues: {Prefix: "⁉️ "}, Issue: {Prefix: " ▪ ", LowPrefix: lowIndent}, // Indented bullet Check: {Prefix: "✔️ "}, + Celebration: {Prefix: "🎉 "}, // Specialized purpose styles ISODownload: {Prefix: "💿 "}, @@ -85,6 +87,7 @@ var styles = map[StyleEnum]style{ Caching: {Prefix: "🤹 "}, StartingVM: {Prefix: "🔥 "}, StartingNone: {Prefix: "🤹 "}, + Provisioner: {Prefix: "ℹ️ "}, Resetting: {Prefix: "🔄 "}, DeletingHost: {Prefix: "🔥 "}, Copying: {Prefix: "✨ "}, @@ -151,19 +154,21 @@ func applyStyle(style StyleEnum, useColor bool, format string) string { return applyPrefix(s.Prefix, format) } -func applyTemplateFormatting(style StyleEnum, useColor bool, format string, a map[string]interface{}) string { +func applyTemplateFormatting(style StyleEnum, useColor bool, format string, a ...V) string { + if a == nil { + a = []V{V{}} + } format = applyStyle(style, useColor, format) var buf bytes.Buffer t, err := template.New(format).Parse(format) if err != nil { - glog.Infof("Initializing template failed. Returning raw string.") + glog.Errorf("unable to parse %q: %v - returning raw string.", format, err) return format } - - err = t.Execute(&buf, a) + err = t.Execute(&buf, a[0]) if err != nil { - glog.Infof("Executing template failed. Returning raw string.") + glog.Errorf("unable to execute %s: %v - returning raw string.", format, err) return format } outStyled := buf.String() diff --git a/pkg/minikube/console/style_enum.go b/pkg/minikube/out/style_enum.go similarity index 96% rename from pkg/minikube/console/style_enum.go rename to pkg/minikube/out/style_enum.go index 43f77594d2..0594bf3591 100644 --- a/pkg/minikube/console/style_enum.go +++ b/pkg/minikube/out/style_enum.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package console +package out // StyleEnum is an enumeration of Style type StyleEnum int @@ -24,6 +24,7 @@ const ( Happy StyleEnum = iota SuccessType FailureType + Celebration Conflict FatalType Notice @@ -55,6 +56,7 @@ const ( Caching StartingVM StartingNone + Provisioner Resetting DeletingHost Copying @@ -79,4 +81,5 @@ const ( Unmount MountOptions Fileserver + Empty ) diff --git a/pkg/minikube/problem/err_map.go b/pkg/minikube/problem/err_map.go index 316e5ef6d7..1ef7e97365 100644 --- a/pkg/minikube/problem/err_map.go +++ b/pkg/minikube/problem/err_map.go @@ -91,6 +91,11 @@ var vmProblems = map[string]match{ Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver", URL: "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver", }, + "HYPERKIT_NOT_FOUND": { + Regexp: re(`Driver "hyperkit" not found. Do you have the plugin binary .* accessible in your PATH?`), + Advice: "Please install the minikube hyperkit VM driver, or select an alternative --vm-driver", + URL: "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver", + }, "KVM2_RESTART_NO_IP": { Regexp: re(`Error starting stopped host: Machine didn't return an IP after 120 seconds`), Advice: "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.", @@ -144,6 +149,12 @@ var vmProblems = map[string]match{ Advice: "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=` to `minikube start`", URL: "https://docs.docker.com/machine/drivers/hyper-v/", }, + "HYPERV_POWERSHELL_NOT_FOUND": { + Regexp: re(`Powershell was not found in the path`), + Advice: "To start minikube with HyperV Powershell must be in your PATH`", + URL: "https://docs.docker.com/machine/drivers/hyper-v/", + }, + "HOST_CIDR_CONFLICT": { Regexp: re(`host-only cidr conflicts with the network address of a host interface`), Advice: "Specify an alternate --host-only-cidr value, such as 172.16.0.1/24", diff --git a/pkg/minikube/problem/problem.go b/pkg/minikube/problem/problem.go index a20e09b121..c4e2660f11 100644 --- a/pkg/minikube/problem/problem.go +++ b/pkg/minikube/problem/problem.go @@ -18,9 +18,10 @@ limitations under the License. package problem import ( + "fmt" "regexp" - "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/translate" ) @@ -52,21 +53,21 @@ type match struct { // Display problem metadata to the console func (p *Problem) Display() { - console.ErrStyle(console.FailureType, "Error: [%s] %v", p.ID, p.Err) - console.ErrStyle(console.Tip, "Advice: %s", translate.T(p.Advice)) + out.ErrT(out.FailureType, "Error: [{{.id}}] {{.error}}", out.V{"id": p.ID, "error": p.Err}) + out.ErrT(out.Tip, "Suggestion: {{.advice}}", out.V{"advice": translate.T(p.Advice)}) if p.URL != "" { - console.ErrStyle(console.Documentation, "Documentation: %s", p.URL) + out.ErrT(out.Documentation, "Documentation: {{.url}}", out.V{"url": p.URL}) } if len(p.Issues) == 0 { return } - console.ErrStyle(console.Issues, "Related issues:") + out.ErrT(out.Issues, "Related issues:") issues := p.Issues if len(issues) > 3 { issues = issues[0:3] } for _, i := range issues { - console.ErrStyle(console.Issue, "%s/%d", issueBase, i) + out.ErrT(out.Issue, "{{.url}}", out.V{"url": fmt.Sprintf("%s/%d", issueBase, i)}) } } diff --git a/pkg/minikube/service/service.go b/pkg/minikube/service/service.go index 0748691885..4a22e8c293 100644 --- a/pkg/minikube/service/service.go +++ b/pkg/minikube/service/service.go @@ -41,8 +41,8 @@ import ( clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/proxy" "k8s.io/minikube/pkg/util" ) @@ -284,7 +284,7 @@ func WaitAndMaybeOpenService(api libmachine.API, namespace string, service strin } if len(urls) == 0 { - console.OutStyle(console.Sad, "service %s/%s has no node port", namespace, service) + out.T(out.Sad, "service {{.namespace_name}}/{{.service_name}} has no node port", out.V{"namespace_name": namespace, "service_name": service}) return nil } @@ -292,11 +292,11 @@ func WaitAndMaybeOpenService(api libmachine.API, namespace string, service strin urlString, isHTTPSchemedURL := OptionallyHTTPSFormattedURLString(bareURLString, https) if urlMode || !isHTTPSchemedURL { - console.OutLn(urlString) + out.T(out.Empty, urlString) } else { - console.OutStyle(console.Celebrate, "Opening kubernetes service %s/%s in default browser...", namespace, service) + out.T(out.Celebrate, "Opening kubernetes service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": service}) if err := browser.OpenURL(urlString); err != nil { - console.Err("browser failed to open url: %v", err) + out.ErrT(out.Empty, "browser failed to open url: {{.error}}", out.V{"error": err}) } } } diff --git a/pkg/minikube/sshutil/sshutil_test.go b/pkg/minikube/sshutil/sshutil_test.go index ed336e9aaa..3aa9c4c459 100644 --- a/pkg/minikube/sshutil/sshutil_test.go +++ b/pkg/minikube/sshutil/sshutil_test.go @@ -25,37 +25,43 @@ import ( ) func TestNewSSHClient(t *testing.T) { - s, _ := tests.NewSSHServer() + s, err := tests.NewSSHServer(t) + if err != nil { + t.Fatalf("NewSSHServer: %v", err) + } port, err := s.Start() if err != nil { t.Fatalf("Error starting ssh server: %v", err) } + defer s.Stop() + d := &tests.MockDriver{ Port: port, BaseDriver: drivers.BaseDriver{ IPAddress: "127.0.0.1", SSHKeyPath: "", }, + T: t, } c, err := NewSSHClient(d) if err != nil { t.Fatalf("Unexpected error: %v", err) } + defer c.Close() - cmd := "foo" sess, err := c.NewSession() if err != nil { t.Fatal("Error creating new session for ssh client") } defer sess.Close() + cmd := "foo" if err := sess.Run(cmd); err != nil { - t.Fatalf("Error running command: %s", cmd) + t.Fatalf("Error running %q: %v", cmd, err) } if !s.Connected { - t.Fatalf("Error!") + t.Fatalf("Server not connected") } - if _, ok := s.Commands[cmd]; !ok { t.Fatalf("Expected command: %s", cmd) } diff --git a/pkg/minikube/tests/api_mock.go b/pkg/minikube/tests/api_mock.go index 9c6d87a8e5..241be0023a 100644 --- a/pkg/minikube/tests/api_mock.go +++ b/pkg/minikube/tests/api_mock.go @@ -19,10 +19,15 @@ package tests import ( "encoding/json" "fmt" + "math/rand" + "testing" "github.com/docker/machine/libmachine/auth" "github.com/docker/machine/libmachine/host" + "github.com/docker/machine/libmachine/swarm" + "github.com/golang/glog" "github.com/pkg/errors" + "github.com/spf13/viper" ) // MockAPI is a struct used to mock out libmachine.API @@ -31,18 +36,31 @@ type MockAPI struct { CreateError bool RemoveError bool SaveCalled bool + t *testing.T } // NewMockAPI returns a new MockAPI -func NewMockAPI() *MockAPI { +func NewMockAPI(t *testing.T) *MockAPI { + t.Helper() m := MockAPI{ FakeStore: FakeStore{ Hosts: make(map[string]*host.Host), + T: t, }, + t: t, } return &m } +// Logf logs mock interactions +func (api *MockAPI) Logf(format string, args ...interface{}) { + if api.t == nil { + glog.Infof(format, args...) + return + } + api.t.Logf(format, args...) +} + // Close closes the API. func (api *MockAPI) Close() error { return nil @@ -54,21 +72,44 @@ func (api *MockAPI) NewHost(driverName string, rawDriver []byte) (*host.Host, er if err := json.Unmarshal(rawDriver, &driver); err != nil { return nil, errors.Wrap(err, "error unmarshalling json") } + h := &host.Host{ - DriverName: driverName, - RawDriver: rawDriver, - Driver: &MockDriver{}, - Name: driver.GetMachineName(), - HostOptions: &host.Options{AuthOptions: &auth.Options{}}, + DriverName: driverName, + RawDriver: rawDriver, + Driver: &MockDriver{}, + Name: fmt.Sprintf("mock-machine-%.8f", rand.Float64()), + HostOptions: &host.Options{ + AuthOptions: &auth.Options{}, + SwarmOptions: &swarm.Options{}, + }, } + + // HACK: Make future calls to config.GetMachineName() work properly. + api.Logf("MockAPI.NewHost: Setting profile=%q", h.Name) + viper.Set("profile", h.Name) + + api.Logf("MockAPI.NewHost: %+v", h) return h, nil } +// Load a created mock +func (api *MockAPI) Load(name string) (*host.Host, error) { + h, err := api.FakeStore.Load(name) + api.Logf("MockAPI.Load: %+v - %v", h, err) + return h, err +} + // Create creates the actual host. func (api *MockAPI) Create(h *host.Host) error { + api.Logf("MockAPI.Create: %+v", h) if api.CreateError { return errors.New("error creating host") } + // Propagate test info messages + drv, ok := h.Driver.(*MockDriver) + if ok { + drv.T = api.t + } return h.Driver.Create() } @@ -79,6 +120,7 @@ func (api *MockAPI) List() ([]string, error) { // Remove a host. func (api *MockAPI) Remove(name string) error { + api.Logf("MockAPI.Delete: %s", name) if api.RemoveError { return fmt.Errorf("error removing %s", name) } @@ -90,6 +132,7 @@ func (api *MockAPI) Remove(name string) error { // Save saves a host to disk. func (api *MockAPI) Save(host *host.Host) error { api.SaveCalled = true + api.Logf("MockAPI.Save: %+v", host) return api.FakeStore.Save(host) } diff --git a/pkg/minikube/tests/driver_mock.go b/pkg/minikube/tests/driver_mock.go index 9f5966ef51..f675e8d74a 100644 --- a/pkg/minikube/tests/driver_mock.go +++ b/pkg/minikube/tests/driver_mock.go @@ -17,9 +17,14 @@ limitations under the License. package tests import ( + "testing" + + "k8s.io/minikube/pkg/minikube/constants" + "github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/mcnflag" "github.com/docker/machine/libmachine/state" + "github.com/golang/glog" "github.com/pkg/errors" ) @@ -31,16 +36,28 @@ type MockDriver struct { HostError bool Port int IP string + T *testing.T +} + +// Logf logs mock interactions +func (driver *MockDriver) Logf(format string, args ...interface{}) { + if driver.T == nil { + glog.Infof(format, args...) + return + } + driver.T.Logf(format, args...) } // Create creates a MockDriver instance func (driver *MockDriver) Create() error { + driver.Logf("MockDriver.Create") driver.CurrentState = state.Running return nil } // GetIP returns the IP address func (driver *MockDriver) GetIP() (string, error) { + driver.Logf("MockDriver.GetIP") if driver.IP != "" { return driver.IP, nil } @@ -75,6 +92,7 @@ func (driver *MockDriver) GetSSHKeyPath() string { // GetState returns the state of the driver func (driver *MockDriver) GetState() (state.State, error) { + driver.Logf("MockDriver.GetState: %v", driver.CurrentState) return driver.CurrentState, nil } @@ -85,12 +103,14 @@ func (driver *MockDriver) GetURL() (string, error) { // Kill kills the machine func (driver *MockDriver) Kill() error { + driver.Logf("MockDriver.Kill") driver.CurrentState = state.Stopped return nil } // Remove removes the machine func (driver *MockDriver) Remove() error { + driver.Logf("MockDriver.Remove") if driver.RemoveError { return errors.New("error deleting machine") } @@ -99,6 +119,7 @@ func (driver *MockDriver) Remove() error { // Restart restarts the machine func (driver *MockDriver) Restart() error { + driver.Logf("MockDriver.Restart") driver.CurrentState = state.Running return nil } @@ -110,12 +131,20 @@ func (driver *MockDriver) SetConfigFromFlags(opts drivers.DriverOptions) error { // Start starts the machine func (driver *MockDriver) Start() error { + driver.Logf("MockDriver.Start") driver.CurrentState = state.Running return nil } // Stop stops the machine func (driver *MockDriver) Stop() error { + driver.Logf("MockDriver.Stop") driver.CurrentState = state.Stopped return nil } + +// DriverName returns the name of the driver +func (driver *MockDriver) DriverName() string { + driver.Logf("MockDriver.Name") + return constants.DriverMock +} diff --git a/pkg/minikube/tests/fake_store.go b/pkg/minikube/tests/fake_store.go index 7eb9a59110..d5881f67f4 100644 --- a/pkg/minikube/tests/fake_store.go +++ b/pkg/minikube/tests/fake_store.go @@ -17,6 +17,8 @@ limitations under the License. package tests import ( + "testing" + "github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/mcnerror" ) @@ -24,6 +26,7 @@ import ( // FakeStore implements persist.Store from libmachine type FakeStore struct { Hosts map[string]*host.Host + T *testing.T } // Exists determines if the host already exists. @@ -67,7 +70,7 @@ func (s *FakeStore) Remove(name string) error { } // Save persists a machine in the store -func (s *FakeStore) Save(host *host.Host) error { - s.Hosts[host.Name] = host +func (s *FakeStore) Save(h *host.Host) error { + s.Hosts[h.Name] = h return nil } diff --git a/pkg/minikube/tests/provision_mock.go b/pkg/minikube/tests/provision_mock.go index 721f45d2f4..0b7abd55f1 100644 --- a/pkg/minikube/tests/provision_mock.go +++ b/pkg/minikube/tests/provision_mock.go @@ -81,7 +81,7 @@ func (provisioner *MockProvisioner) SetOsReleaseInfo(info *provision.OsRelease) // GetOsReleaseInfo gets the os-release info func (provisioner *MockProvisioner) GetOsReleaseInfo() (*provision.OsRelease, error) { - return nil, nil + return &provision.OsRelease{}, nil } // AttemptIPContact attempts to contact an IP and port diff --git a/pkg/minikube/tests/ssh_mock.go b/pkg/minikube/tests/ssh_mock.go index cc44bf0c83..ebb9206fc1 100644 --- a/pkg/minikube/tests/ssh_mock.go +++ b/pkg/minikube/tests/ssh_mock.go @@ -25,8 +25,8 @@ import ( "net" "strconv" "sync/atomic" + "testing" - "github.com/golang/glog" "github.com/pkg/errors" "golang.org/x/crypto/ssh" ) @@ -43,16 +43,21 @@ type SSHServer struct { // commandsToOutput can be used to mock what the SSHServer returns for a given command // Only access this with atomic ops commandToOutput atomic.Value + + quit bool + listener net.Listener + t *testing.T } // NewSSHServer returns a NewSSHServer instance, ready for use. -func NewSSHServer() (*SSHServer, error) { - s := &SSHServer{} - s.Transfers = &bytes.Buffer{} - s.Config = &ssh.ServerConfig{ - NoClientAuth: true, +func NewSSHServer(t *testing.T) (*SSHServer, error) { + t.Helper() + s := &SSHServer{ + Transfers: &bytes.Buffer{}, + Config: &ssh.ServerConfig{NoClientAuth: true}, + Commands: map[string]int{}, + t: t, } - s.Commands = make(map[string]int) private, err := rsa.GenerateKey(rand.Reader, 2014) if err != nil { @@ -72,102 +77,103 @@ type execRequest struct { Command string } -// Main loop, listen for connections and store the commands. -func (s *SSHServer) mainLoop(listener net.Listener) { - go func() { - for { - nConn, err := listener.Accept() - go func() { - if err != nil { - return - } - - _, chans, reqs, err := ssh.NewServerConn(nConn, s.Config) - if err != nil { - return - } - // The incoming Request channel must be serviced. - go ssh.DiscardRequests(reqs) - - // Service the incoming Channel channel. - for newChannel := range chans { - if newChannel.ChannelType() == "session" { - s.SetSessionRequested(true) - } - channel, requests, err := newChannel.Accept() - s.Connected = true - if err != nil { - return - } - - for req := range requests { - glog.Infoln("Got Req: ", req.Type) - // Store anything that comes in over stdin. - s.handleRequest(channel, req) - } - } - }() +// Serve loop, listen for connections and store the commands. +func (s *SSHServer) serve() { + for { + s.t.Logf("Accepting...") + c, err := s.listener.Accept() + if s.quit { + return } - }() + if err != nil { + s.t.Errorf("Listener: %v", err) + return + } + go s.handleIncomingConnection(c) + } +} + +// handle an incoming ssh connection +func (s *SSHServer) handleIncomingConnection(c net.Conn) { + _, chans, reqs, err := ssh.NewServerConn(c, s.Config) + if err != nil { + s.t.Logf("newserverconn error: %v", err) + return + } + // The incoming Request channel must be serviced. + go ssh.DiscardRequests(reqs) + + // Service the incoming Channel channel. + for newChannel := range chans { + if newChannel.ChannelType() == "session" { + s.SetSessionRequested(true) + } + channel, requests, err := newChannel.Accept() + if err != nil { + s.t.Logf("ch accept err: %v", err) + return + } + s.Connected = true + for req := range requests { + s.handleRequest(channel, req) + } + } } func (s *SSHServer) handleRequest(channel ssh.Channel, req *ssh.Request) { go func() { if _, err := io.Copy(s.Transfers, channel); err != nil { - panic(fmt.Sprintf("copy failed: %v", err)) + s.t.Errorf("copy failed: %v", err) } channel.Close() }() switch req.Type { case "exec": + s.t.Logf("exec request received: %+v", req) if err := req.Reply(true, nil); err != nil { - panic(fmt.Sprintf("reply failed: %v", err)) + s.t.Errorf("reply failed: %v", err) } // Note: string(req.Payload) adds additional characters to start of input. var cmd execRequest if err := ssh.Unmarshal(req.Payload, &cmd); err != nil { - glog.Errorf("Unmarshall encountered error: %v with req: %v", err, req.Type) - return + s.t.Errorf("unmarshal failed: %v", err) } s.Commands[cmd.Command] = 1 // Write specified command output as mocked ssh output if val, err := s.GetCommandToOutput(cmd.Command); err == nil { if _, err := channel.Write([]byte(val)); err != nil { - glog.Errorf("Write failed: %v", err) - return + s.t.Errorf("Write failed: %v", err) } } if _, err := channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0}); err != nil { - glog.Errorf("SendRequest failed: %v", err) - return + s.t.Errorf("SendRequest failed: %v", err) } case "pty-req": + s.t.Logf("pty request received: %+v", req) if err := req.Reply(true, nil); err != nil { - glog.Errorf("Reply failed: %v", err) - return + s.t.Errorf("Reply failed: %v", err) } if _, err := channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0}); err != nil { - glog.Errorf("SendRequest failed: %v", err) - return + s.t.Errorf("SendRequest failed: %v", err) } } } -// Start starts the mock SSH Server, and returns the port it's listening on. +// Start the mock SSH Server func (s *SSHServer) Start() (int, error) { - listener, err := net.Listen("tcp", "127.0.0.1:0") + l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { return 0, errors.Wrap(err, "Error creating tcp listener for ssh server") } + s.listener = l + s.t.Logf("Listening on %s", s.listener.Addr()) + go s.serve() - s.mainLoop(listener) - - // Parse and return the port. - _, p, err := net.SplitHostPort(listener.Addr().String()) + _, p, err := net.SplitHostPort(s.listener.Addr().String()) if err != nil { return 0, errors.Wrap(err, "Error splitting host port") } @@ -178,6 +184,13 @@ func (s *SSHServer) Start() (int, error) { return port, nil } +// Stop the mock SSH server +func (s *SSHServer) Stop() { + s.t.Logf("Stopping") + s.quit = true + s.listener.Close() +} + // SetCommandToOutput sets command to output func (s *SSHServer) SetCommandToOutput(cmdToOutput map[string]string) { s.commandToOutput.Store(cmdToOutput) diff --git a/pkg/minikube/tunnel/cluster_inspector_test.go b/pkg/minikube/tunnel/cluster_inspector_test.go index d013ca04e1..59dfaf14fd 100644 --- a/pkg/minikube/tunnel/cluster_inspector_test.go +++ b/pkg/minikube/tunnel/cluster_inspector_test.go @@ -34,7 +34,7 @@ import ( func TestAPIError(t *testing.T) { machineName := "nonexistentmachine" - machineAPI := tests.NewMockAPI() + machineAPI := tests.NewMockAPI(t) configLoader := &stubConfigLoader{} inspector := &clusterInspector{ machineAPI, configLoader, machineName, diff --git a/pkg/minikube/tunnel/test_doubles.go b/pkg/minikube/tunnel/test_doubles.go index c461d8dfd8..8f2e4aaef0 100644 --- a/pkg/minikube/tunnel/test_doubles.go +++ b/pkg/minikube/tunnel/test_doubles.go @@ -86,6 +86,6 @@ type stubConfigLoader struct { e error } -func (l *stubConfigLoader) LoadConfigFromFile(profile string) (*config.Config, error) { +func (l *stubConfigLoader) LoadConfigFromFile(profile string, miniHome ...string) (*config.Config, error) { return l.c, l.e } diff --git a/pkg/storage/storage_provisioner.go b/pkg/storage/storage_provisioner.go index cc2aef0731..953b80aba9 100644 --- a/pkg/storage/storage_provisioner.go +++ b/pkg/storage/storage_provisioner.go @@ -23,7 +23,6 @@ import ( "github.com/golang/glog" "github.com/pkg/errors" - "github.com/r2d4/external-storage/lib/controller" core "k8s.io/api/core/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -31,6 +30,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + "sigs.k8s.io/sig-storage-lib-external-provisioner/controller" ) const provisionerName = "k8s.io/minikube-hostpath" @@ -55,7 +55,7 @@ func NewHostPathProvisioner() controller.Provisioner { var _ controller.Provisioner = &hostPathProvisioner{} // Provision creates a storage asset and returns a PV object representing it. -func (p *hostPathProvisioner) Provision(options controller.VolumeOptions) (*core.PersistentVolume, error) { +func (p *hostPathProvisioner) Provision(options controller.ProvisionOptions) (*core.PersistentVolume, error) { glog.Infof("Provisioning volume %v", options) path := path.Join(p.pvDir, options.PVName) if err := os.MkdirAll(path, 0777); err != nil { @@ -75,7 +75,7 @@ func (p *hostPathProvisioner) Provision(options controller.VolumeOptions) (*core }, }, Spec: core.PersistentVolumeSpec{ - PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy, + PersistentVolumeReclaimPolicy: *options.StorageClass.ReclaimPolicy, AccessModes: options.PVC.Spec.AccessModes, Capacity: core.ResourceList{ core.ResourceStorage: options.PVC.Spec.Resources.Requests[core.ResourceStorage], diff --git a/pkg/util/downloader.go b/pkg/util/downloader.go index da84a03424..03b130a56d 100644 --- a/pkg/util/downloader.go +++ b/pkg/util/downloader.go @@ -25,8 +25,8 @@ import ( "github.com/golang/glog" download "github.com/jimmidyson/go-download" "github.com/pkg/errors" - "k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/out" ) const fileScheme = "file" @@ -76,7 +76,7 @@ func (f DefaultDownloader) CacheMinikubeISOFromURL(isoURL string) error { options.ChecksumHash = crypto.SHA256 } - console.OutStyle(console.ISODownload, "Downloading Minikube ISO ...") + out.T(out.ISODownload, "Downloading Minikube ISO ...") if err := download.ToFile(isoURL, f.GetISOCacheFilepath(isoURL), options); err != nil { return errors.Wrap(err, isoURL) } diff --git a/pkg/util/kubernetes.go b/pkg/util/kubernetes.go index 0b3cc90e99..225cba3af0 100644 --- a/pkg/util/kubernetes.go +++ b/pkg/util/kubernetes.go @@ -17,6 +17,7 @@ limitations under the License. package util import ( + "context" "fmt" "time" @@ -35,6 +36,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" + watchtools "k8s.io/client-go/tools/watch" "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/minikube/pkg/minikube/proxy" ) @@ -42,8 +44,8 @@ import ( var ( // ReasonableMutateTime is how long to wait for basic object mutations, such as deletions, to show up ReasonableMutateTime = time.Minute * 2 - // ReasonableStartTime is how long to wait for pods to start, considering dependency chains & slow networks. - ReasonableStartTime = time.Minute * 10 + // ReasonableStartTime is how long to wait for pods to start + ReasonableStartTime = time.Minute * 5 ) // PodStore stores pods @@ -69,9 +71,14 @@ func (s *PodStore) Stop() { } // GetClient gets the client from config -func GetClient() (kubernetes.Interface, error) { +func GetClient(kubectlContext ...string) (kubernetes.Interface, error) { loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() configOverrides := &clientcmd.ConfigOverrides{} + if kubectlContext != nil { + configOverrides = &clientcmd.ConfigOverrides{ + CurrentContext: kubectlContext[0], + } + } kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides) config, err := kubeConfig.ClientConfig() if err != nil { @@ -191,7 +198,11 @@ func WaitForRCToStabilize(c kubernetes.Interface, ns, name string, timeout time. if err != nil { return err } - _, err = watch.Until(timeout, w, func(event watch.Event) (bool, error) { + + ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout) + defer cancel() + + _, err = watchtools.UntilWithoutRetry(ctx, w, func(event watch.Event) (bool, error) { if event.Type == watch.Deleted { return false, apierr.NewNotFound(schema.GroupResource{Resource: "replicationcontrollers"}, "") } @@ -221,7 +232,11 @@ func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeo if err != nil { return err } - _, err = watch.Until(timeout, w, func(event watch.Event) (bool, error) { + + ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout) + defer cancel() + + _, err = watchtools.UntilWithoutRetry(ctx, w, func(event watch.Event) (bool, error) { if event.Type == watch.Deleted { return false, apierr.NewNotFound(schema.GroupResource{Resource: "deployments"}, "") } diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 15a228b6e7..7fdb2bf217 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -21,8 +21,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" - "net/http" "os" "os/user" "path/filepath" @@ -32,9 +30,9 @@ import ( units "github.com/docker/go-units" "github.com/golang/glog" - retryablehttp "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/out" ) // ErrPrefix notes an error @@ -62,7 +60,7 @@ func CalculateSizeInMB(humanReadableSize string) int { } size, err := units.FromHumanSize(humanReadableSize) if err != nil { - exit.WithCode(exit.Config, "Invalid size passed in argument: %v", err) + exit.WithCodeT(exit.Config, "Invalid size passed in argument: {{.error}}", out.V{"error": err}) } return int(size / units.MB) @@ -135,24 +133,6 @@ func RetryAfter(attempts int, callback func() error, d time.Duration) (err error return m.ToError() } -// ParseSHAFromURL downloads and reads a SHA checksum from an URL -func ParseSHAFromURL(url string) (string, error) { - r, err := retryablehttp.Get(url) - if err != nil { - return "", errors.Wrap(err, "Error downloading checksum.") - } else if r.StatusCode != http.StatusOK { - return "", errors.Errorf("Error downloading checksum. Got HTTP Error: %s", r.Status) - } - - defer r.Body.Close() - body, err := ioutil.ReadAll(r.Body) - if err != nil { - return "", errors.Wrap(err, "Error reading checksum.") - } - - return strings.Trim(string(body), "\n"), nil -} - // GetBinaryDownloadURL returns a suitable URL for the platform func GetBinaryDownloadURL(version, platform string) string { switch platform { diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go index 611f137a47..480e28a756 100644 --- a/pkg/util/utils_test.go +++ b/pkg/util/utils_test.go @@ -19,9 +19,6 @@ package util import ( "bytes" "fmt" - "io" - "net/http" - "net/http/httptest" "strings" "sync" "testing" @@ -88,45 +85,6 @@ func TestRetryNotRetriableError(t *testing.T) { } } -type getTestArgs struct { - input string - expected string - expectedError bool -} - -var testSHAString = "test" - -func TestParseSHAFromURL(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if _, err := io.WriteString(w, testSHAString); err != nil { - t.Fatalf("WriteString: %v", err) - } - })) - serverBadResponse := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - if _, err := w.Write([]byte("500 HTTP status code returned!")); err != nil { - t.Fatalf("Write: %v", err) - } - })) - - argsList := [...]getTestArgs{ - {server.URL, testSHAString, false}, - {serverBadResponse.URL, "", true}, - {"abc", "", true}, - } - for _, args := range argsList { - url, err := ParseSHAFromURL(args.input) - wasError := err != nil - if wasError != args.expectedError { - t.Errorf("ParseSHAFromURL Expected error was: %t, Actual Error was: %s", - args.expectedError, err) - } - if url != args.expected { - t.Errorf("ParseSHAFromURL: Expected %s, Actual: %s", args.expected, url) - } - } -} - func TestMultiError(t *testing.T) { m := MultiError{} diff --git a/site/README.md b/site/README.md new file mode 100644 index 0000000000..271377f154 --- /dev/null +++ b/site/README.md @@ -0,0 +1,56 @@ +[Docsy](https://github.com/google/docsy) is a Hugo theme for technical documentation sites, providing easy site navigation, structure, and more. This **Docsy Example Project** uses the Docsy theme, as well as providing a skeleton documentation structure for you to use. You can either copy this project and edit it with your own content, or use the theme in your projects like any other [Hugo theme](https://gohugo.io/themes/installing-and-using-themes/). + +This Docsy Example Project is hosted at [https://goldydocs.netlify.com/](https://goldydocs.netlify.com/). + +You can find detailed theme instructions in the Docsy user guide: https://docsydocs.netlify.com/docs/ + +This is not an officially supported Google product. This project is currently maintained. + +## Cloning the Docsy Example Project + +The following will give you a project that is set up and ready to use (don't forget to use `--recurse-submodules` or you won't pull down some of the code you need to generate a working site). The `hugo server` command builds and serves the site. If you just want to build the site, run `hugo` instead. + +```bash +git clone --recurse-submodules --depth 1 https://github.com/google/docsy-example.git +cd docsy-example +hugo server +``` + +The theme is included as a Git submodule: + +```bash +▶ git submodule + a053131a4ebf6a59e4e8834a42368e248d98c01d themes/docsy (heads/master) +``` + +If you want to do SCSS edits and want to publish these, you need to install `PostCSS` (not needed for `hugo server`): + +```bash +npm install +``` + + + +## Running the website locally + +Once you've cloned the site repo, from the repo root folder, run: + +``` +hugo server +``` diff --git a/site/archetypes/default.md b/site/archetypes/default.md deleted file mode 100644 index 00e77bd79b..0000000000 --- a/site/archetypes/default.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -date: {{ .Date }} -draft: true ---- - diff --git a/site/assets/icons/logo.svg b/site/assets/icons/logo.svg new file mode 100644 index 0000000000..c5bea2b2cc --- /dev/null +++ b/site/assets/icons/logo.svg @@ -0,0 +1,23 @@ + + + + minikube + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/assets/scss/_variables_project.scss b/site/assets/scss/_variables_project.scss new file mode 100644 index 0000000000..e737450f4e --- /dev/null +++ b/site/assets/scss/_variables_project.scss @@ -0,0 +1,151 @@ +// minkube CSS overrides /// + +// minikube colors, taken from the logo +$mk-dark: #306EE5; +$mk-medium: #1FC3CF; +$mk-light:#C7EAEC; +$mk-verydark: darken($mk-dark, 15%); + +// bootstrap colors +$dark: #403F4C !default; +$blue: #72A1E5 !default; +$orange: #BA5A31 !default; +$gray-100: #f8f9fa !default; +$gray-200: #eee !default; +$gray-300: #dee2e6 !default; +$gray-400: #ccc !default; +$gray-500: #adb5bd !default; +$gray-600: #888 !default; +$gray-700: #495057 !default; +$gray-800: #333 !default; +$gray-900: #222 !default; +$black: #000 !default; + +$primary: #f2771a !default; +$primary-light: $mk-light; +$secondary: #403F4C; +$success: #3772FF !default; +$info: #C0E0DE !default; +$warning: #ED6A5A !default; +$danger: #ED6A5A !default; +$white: #fff !default; +$light: $mk-light; +$medium: $mk-medium; + + +// Navigation bar +$navbar-dark-color: $mk-dark; +$navbar-dark-hover-color: $mk-light !default; +$navbar-dark-active-color: $mk-light !default; +$navbar-dark-disabled-color: rgba($white, 0.25) !default; +.td-navbar { + background: $white !important; + border-bottom: 1px solid $mk-light; + + .navbar-logo { + svg { + display: inline-block; + height: 50px; + width: auto; + margin-right: 10px; + } + } + a.navbar-brand { + color: $gray-900 !important; + } + span.text-uppercase { + text-transform: none !important; + } +} + +// Inline images +div.card.rounded { + border: none; +} + +// Links +$link-color: $mk-dark !default; +$link-decoration: none !default; +$link-hover-color: darken($link-color, 15%) !default; +$link-hover-decoration: none !default; + +// Welcome to minikube! box +.td-box--white:nth-child(1) { + + // News + ul { + margin-top: 1rem; + list-style: none; + color: $gray-700; + padding-left: 0; + } +} + +// Sales pitch box +.td-box--1 { + background-color: $mk-dark !important; + + // Increase from 1.25 for improved readability + .h4 { + line-height: 1.6 !important; + } + + // Control the presentation of the screenshot + .p-2 { + padding: 0 !important; + margin-left: auto; + margin-right: auto; + } + .card { + border-radius: 0 !important; + border: 2px solid $mk-verydark !important; + } + .card-img-top { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + // Make sure the arrow color matches our override + .td-arrow-down::before { + border-color: $mk-dark transparent transparent transparent !important; + } + + // Left is best. + .text-center { + text-align: left !important; + } +} + +// Features box +.td-box--white { + // Center-aligned bullets look bad. + .text-center ul { + text-align: left; + margin-left: auto; + margin-right: auto; + max-width: 15em; + } + div.mb-5:nth-child(3) ul { + max-width: 10em; + } +} + +// Shorten footer box by 4x +footer.bg-dark { + padding-top: 1rem !important; + min-height: 4rem !important; + div.py-2 { + padding-top: 0 !important; + } +} + +// If we're using icons for bullets, de-ident +.fa-ul { + padding-left: 0em !important; + margin-left: 1em !important; +} + +// Reduce section padding by 1rem +section.td-box--height-auto { + padding-bottom: 3rem !important; +} \ No newline at end of file diff --git a/site/config.toml b/site/config.toml index 051ca80abc..3450c453d4 100644 --- a/site/config.toml +++ b/site/config.toml @@ -1,48 +1,118 @@ title = "minikube" baseURL = "https://minikube.sigs.k8s.io" -languageCode = "en-us" +enableRobotsTXT = true -# code highlighting -pygmentsCodeFences = true -pygmentsCodefencesGuessSyntax = true -pygmentsUseClasses = true +# Hugo allows theme composition (and inheritance). The precedence is from left to right. +theme = ["docsy"] +# Will give values to .Lastmod etc. +enableGitInfo = true + +# Language settings +contentDir = "content/en" +defaultContentLanguage = "en" +defaultContentLanguageInSubdir = false +# Useful when translating. +enableMissingTranslationPlaceholders = true -# unused disableKinds = ["taxonomy", "taxonomyTerm"] -themesDir = "themes" -theme = "hugo-whisper-theme" +# Highlighting config +pygmentsCodeFences = true +pygmentsUseClasses = false +# Use the new Chroma Go highlighter in Hugo. +pygmentsUseClassic = false +#pygmentsOptions = "linenos=table" +# See https://help.farbox.com/pygments.html +pygmentsStyle = "tango" -[[menu.main]] - name = "Home" - url = "/" - weight = 1 + # First one is picked as the Twitter card image if not set on page. + #images = ["images/project-illustration.png"] -[[menu.main]] - name = "Docs" - url = "/docs/" - weight = 2 +# Configure how URLs look like per section. +[permalinks] +blog = "/:section/:year/:month/:day/:slug/" + +## Configuration for BlackFriday markdown parser: https://github.com/russross/blackfriday +[blackfriday] +plainIDAnchors = true +hrefTargetBlank = true +angledQuotes = false +latexDashes = true + +# Image processing configuration. +[imaging] +resampleFilter = "CatmullRom" +quality = 75 +anchor = "smart" + +[services] +[services.googleAnalytics] +# Comment out the next line to disable GA tracking. Also disables the feature described in [params.ui.feedback]. +#id = "UA-00000000-0" + +# Language configuration +[languages] +[languages.en] +title = "minikube" +description = "minikube is local Kubernetes" +languageName = "English" +weight = 1 [params] - google_analytics_id="" - homepage_button_link = '/docs' - homepage_button_text = 'Read The Docs' - homepage_intro = 'minikube implements a local Kubernetes cluster on macOS, Linux, and Windows.' - homepage_image = 'https://github.com/kubernetes/minikube/raw/master/images/start.jpg' +copyright = "The Kubernetes Authors -- " +# The latest release of minikube +latest_release = "1.2.0" - [params.homepage_meta_tags] - meta_description = "minikube desc" - meta_og_title = "minikube" - meta_og_type = "website" - meta_og_url = "https://minikube.sigs.k8s.io" - meta_og_image = "https://raw.githubusercontent.com/JugglerX/hugo-whisper-theme/master/images/tn.png" +privacy_policy = "" - [params.logo] - mobile = "https://github.com/kubernetes/minikube/raw/master/images/logo/logo.png" - standard = "https://github.com/kubernetes/minikube/raw/master/images/logo/logo.png" +# Menu title if your navbar has a versions selector to access old versions of your site. +# This menu appears only if you have at least one [params.versions] set. +version_menu = "Releases" +# Repository configuration (URLs for in-page links to opening issues and suggesting changes) +github_repo = "http://github.com/minikube/kubernetes" +# An optional link to a related project repo. For example, the sibling repository where your product code lives. +github_project_repo = "" +# Specify a value here if your content directory is not in your repo's root directory +github_subdir = "/site/content" +# Google Custom Search Engine ID. Remove or comment out to disable search. +gcs_engine_id = "005331096405080631692:s7c4yfpw9sy" +# User interface configuration +[params.ui] +# Enable to show the side bar menu in its compact state. +sidebar_menu_compact = false +# Set to true to disable breadcrumb navigation. +breadcrumb_disable = false +# Set to true to hide the sidebar search box (the top nav search box will still be displayed if search is enabled) +sidebar_search_disable = false +# Set to false if you don't want to display a logo (/assets/icons/logo.svg) in the top nav bar +navbar_logo = true +# Adds a H2 section titled "Feedback" to the bottom of each doc. The responses are sent to Google Analytics as events. +# This feature depends on [services.googleAnalytics] and will be disabled if "services.googleAnalytics.id" is not set. +# If you want this feature, but occasionally need to remove the "Feedback" section from a single page, +# add "hide_feedback: true" to the page's front matter. +[params.ui.feedback] +enable = true +# The responses that the user sees after clicking "yes" (the page was helpful) or "no" (the page was not helpful). +yes = 'Glad to hear it! Please tell us how we can improve.' +no = 'Sorry to hear that. Please tell us how we can improve.' + +[params.links] +# End user relevant links. These will show up on left side of footer and in the community page if you have one. +[[params.links.user]] + name = "Slack" + url = "https://kubernetes.slack.com/messages/C1F5CT6Q1" + icon = "fab fa-slack" + desc = "Chat with other minikube users & developers" + +# Developer relevant links. These will show up on right side of footer and in the community page if you have one. +[[params.links.developer]] + name = "GitHub" + url = "https://github.com/kubernetes/minikube" + icon = "fab fa-github" + desc = "Development takes place here!" diff --git a/site/content/_index.md b/site/content/_index.md deleted file mode 100644 index 2c670cedf5..0000000000 --- a/site/content/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "minikube" -date: 2019-06-15T09:19:25+08:00 -draft: true ---- - -minikube implements a local Kubernetes cluster on macOS, Linux, and Windows. - -This is just a test website. - diff --git a/site/content/en/_index.html b/site/content/en/_index.html new file mode 100644 index 0000000000..12d8977f91 --- /dev/null +++ b/site/content/en/_index.html @@ -0,0 +1,108 @@ +--- +title: "minikube" +resources: +- src: "logo.png" + title: "logo" + +- src: "start.jpg" + title: "start" +--- + + +
+
+
+
+

Welcome to minikube!

+

Local Kubernetes, focused on application development & education

+ + Get Started + + + View Repository + +
+
+ {{< imgproc "logo" Fit "220x220" >}}{{< /imgproc >}} +
+
+
+
+ + + +{{< blocks/lead >}} + +
+

Instantly productive.

+ +A single command away from reproducing your production environment, from the comfort of localhost. + +{{< imgproc "start" Fit "730x239" >}}{{< /imgproc >}} + +

Highlights

+
    +
  • Always supports the latest Kubernetes release (as well as previous versions)
  • +
  • Cross-platform (Linux, macOS, Windows)
  • +
  • Infinitely configurable local development environment
  • +
  • Multiple container runtimes (crio, containerd, docker, gvisor)
  • +
  • Provides a Docker API endpoint
  • +
+
+ + + +{{< /blocks/lead >}} + + +{{< blocks/section color="white" >}} +{{% blocks/feature icon="fa-star" title="Developer focused" %}} +- [LoadBalancer emulation](https://github.com/kubernetes/minikube/blob/master/docs/tunnel.md) +- [Addons Marketplace](https://github.com/kubernetes/minikube/blob/master/docs/addons.md) +- [Integrated Dashboard](https://github.com/kubernetes/minikube/blob/master/docs/dashboard.md) +- [GPU support](https://github.com/kubernetes/minikube/blob/master/docs/gpu.md) +- Reusable Docker daemon +{{% /blocks/feature %}} + +{{% blocks/feature icon="fa-cogs" title="Infinitely configurable" %}} +- Any container runtime +- Any Kubernetes version +- Any apiserver, kubelet, controller, etcd, proxy, or scheduler option +{{% /blocks/feature %}} + +{{% blocks/feature icon="fa-thumbs-up" title="Cross-platform" %}} +- Bare-metal +- HyperKit +- Hyper-V +- KVM +- VirtualBox +- VMware +{{% /blocks/feature %}} +{{< /blocks/section >}} + +{{< blocks/section color="light" >}} +{{% blocks/feature icon="fab fa-slack" title="Chat with us on Slack" %}} + + + + +The #minikube channel is ready to answer your questions. +{{% /blocks/feature %}} + +{{% blocks/feature icon="fab fa-github" title="Contributions welcome" %}} + + + + +Want to join the fun on Github? New users are always welcome! +{{% /blocks/feature %}} + +{{% blocks/feature icon="fas fa-bullhorn" title="Make your voice heard" %}} + + + + +Have time for 5 quick questions? We would love to hear from you. + +{{% /blocks/feature %}} +{{< /blocks/section >}} diff --git a/site/content/en/blog/_index.md b/site/content/en/blog/_index.md new file mode 100644 index 0000000000..43820eb17d --- /dev/null +++ b/site/content/en/blog/_index.md @@ -0,0 +1,13 @@ +--- +title: "Docsy Blog" +linkTitle: "Blog" +menu: + main: + weight: 30 +--- + + +This is the **blog** section. It has two categories: News and Releases. + +Files in these directories will be listed in reverse chronological order. + diff --git a/site/content/en/blog/news/_index.md b/site/content/en/blog/news/_index.md new file mode 100644 index 0000000000..13d25eaa45 --- /dev/null +++ b/site/content/en/blog/news/_index.md @@ -0,0 +1,8 @@ + +--- +title: "News About Docsy" +linkTitle: "News" +weight: 20 +--- + + diff --git a/site/content/en/blog/news/first-post/featured-sunset-get.png b/site/content/en/blog/news/first-post/featured-sunset-get.png new file mode 100644 index 0000000000..db3373c0bf Binary files /dev/null and b/site/content/en/blog/news/first-post/featured-sunset-get.png differ diff --git a/site/content/en/blog/news/first-post/index.md b/site/content/en/blog/news/first-post/index.md new file mode 100644 index 0000000000..b6bfb47722 --- /dev/null +++ b/site/content/en/blog/news/first-post/index.md @@ -0,0 +1,46 @@ +--- +date: 2018-10-06 +title: "Easy documentation with Docsy" +linkTitle: "Announcing Docsy" +description: "The Docsy Hugo theme lets project maintainers and contributors focus on content, not on reinventing a website infrastructure from scratch" +author: Riona MacNamara ([@rionam](https://twitter.com/bepsays)) +resources: +- src: "**.{png,jpg}" + title: "Image #:counter" + params: + byline: "Photo: Riona MacNamara / CC-BY-CA" +--- + +**This is a typical blog post that includes images.** + +The front matter specifies the date of the blog post, its title, a short description that will be displayed on the blog landing page, and its author. + +## Including images + +Here's an image (`featured-sunset-get.png`) that includes a byline and a caption. + +{{< imgproc sunset Fill "600x300" >}} +Fetch and scale an image in the upcoming Hugo 0.43. +{{< /imgproc >}} + +The front matter of this post specifies properties to be assigned to all image resources: + +``` +resources: +- src: "**.{png,jpg}" + title: "Image #:counter" + params: + byline: "Photo: Riona MacNamara / CC-BY-CA" +``` + +To include the image in a page, specify its details like this: + +``` +{{< imgproc sunset Fill "600x300" >}} +Fetch and scale an image in the upcoming Hugo 0.43. +{{< /imgproc >}} +``` + +The image will be rendered at the size and byline specified in the front matter. + + diff --git a/site/content/en/blog/news/second-post.md b/site/content/en/blog/news/second-post.md new file mode 100755 index 0000000000..4277e67178 --- /dev/null +++ b/site/content/en/blog/news/second-post.md @@ -0,0 +1,241 @@ + +--- +title: "The second blog post" +linkTitle: "Second blog post" +date: 2018-10-06 +description: > + A short lead descripton about this content page. Text here can also be **bold** or _italic_ and can even be split over multiple paragraphs. +--- + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://github.com) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header + +This is a normal paragraph following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Lorem markdownum tuta hospes stabat; idem saxum facit quaterque repetito +occumbere, oves novem gestit haerebat frena; qui. Respicit recurvam erat: +pignora hinc reppulit nos **aut**, aptos, ipsa. + +Meae optatos *passa est* Epiros utiliter *Talibus niveis*, hoc lata, edidit. +Dixi ad aestum. + +## Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Salt-n-Pepa +* Bel Biv DeVoe +* Kid 'N Play + +And an ordered list: + +1. Michael Jackson +2. Michael Bolton +3. Michael Bublé + +And an unordered task list: + +- [x] Create a sample markdown document +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Steal underpants +- ? +- [ ] Profit! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition terms are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +Large images should always scale down and fit in the content container. + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note:" >}}This is an alert with a title.{{< /alert >}} +{{< alert type="success" >}}This is a successful alert.{{< /alert >}} +{{< alert type="warning" >}}This is a warning!{{< /alert >}} +{{< alert type="warning" title="Warning!" >}}This is a warning with a title!{{< /alert >}} + + +## Sizing + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Parameters available + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using pixels + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using rem + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +## Memory + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### RAM to use + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### More is better + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Used RAM + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/site/content/en/blog/releases/_index.md b/site/content/en/blog/releases/_index.md new file mode 100644 index 0000000000..b1d9eb4ff3 --- /dev/null +++ b/site/content/en/blog/releases/_index.md @@ -0,0 +1,8 @@ + +--- +title: "New Releases" +linkTitle: "Releases" +weight: 20 +--- + + diff --git a/site/content/en/blog/releases/in-depth-monoliths-detailed-spec.md b/site/content/en/blog/releases/in-depth-monoliths-detailed-spec.md new file mode 100755 index 0000000000..695908f741 --- /dev/null +++ b/site/content/en/blog/releases/in-depth-monoliths-detailed-spec.md @@ -0,0 +1,241 @@ + +--- +title: "Another Great Release" +linkTitle: "Release New Features" +date: 2018-01-04 +description: > + A short lead descripton about this content page. Text here can also be **bold** or _italic_ and can even be split over multiple paragraphs. +--- + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://github.com) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. There should be whitespace between paragraphs. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header + +This is a normal paragraph following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Lorem markdownum tuta hospes stabat; idem saxum facit quaterque repetito +occumbere, oves novem gestit haerebat frena; qui. Respicit recurvam erat: +pignora hinc reppulit nos **aut**, aptos, ipsa. + +Meae optatos *passa est* Epiros utiliter *Talibus niveis*, hoc lata, edidit. +Dixi ad aestum. + +## Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Salt-n-Pepa +* Bel Biv DeVoe +* Kid 'N Play + +And an ordered list: + +1. Michael Jackson +2. Michael Bolton +3. Michael Bublé + +And an unordered task list: + +- [x] Create a sample markdown document +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Steal underpants +- ? +- [ ] Profit! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition terms are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +Large images should always scale down and fit in the content container. + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note:" >}}This is an alert with a title.{{< /alert >}} +{{< alert type="success" >}}This is a successful alert.{{< /alert >}} +{{< alert type="warning" >}}This is a warning!{{< /alert >}} +{{< alert type="warning" title="Warning!" >}}This is a warning with a title!{{< /alert >}} + + +## Sizing + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Parameters available + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using pixels + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Using rem + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +## Memory + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### RAM to use + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### More is better + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Used RAM + +Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/site/content/en/community/_index.md b/site/content/en/community/_index.md new file mode 100644 index 0000000000..cdade16308 --- /dev/null +++ b/site/content/en/community/_index.md @@ -0,0 +1,8 @@ +--- +title: Community +menu: + main: + weight: 40 +--- + + diff --git a/site/content/en/docs/Concepts/_index.md b/site/content/en/docs/Concepts/_index.md new file mode 100644 index 0000000000..9cc7cd6ff4 --- /dev/null +++ b/site/content/en/docs/Concepts/_index.md @@ -0,0 +1,17 @@ +--- +title: "Concepts" +linkTitle: "Concepts" +weight: 4 +description: > + Concepts that users and contributors should be aware of. +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +For many projects, users may not need much information beyond the information in the [Overview](/docs/overview/), so this section is **optional**. However if there are areas where your users will need a more detailed understanding of a given term or feature in order to do anything useful with your project (or to not make mistakes when using it) put that information in this section. For example, you may want to add some conceptual pages if you have a large project with many components and a complex architecture. + +Remember to focus on what the user needs to know, not just what you think is interesting about your project! If they don’t need to understand your original design decisions to use or contribute to the project, don’t put them in, or include your design docs in your repo and link to them. Similarly, most users will probably need to know more about how features work when in use rather than how they are implemented. Consider a separate architecture page for more detailed implementation and system design information that potential project contributors can consult. + + diff --git a/site/content/en/docs/Concepts/principles.en.md b/site/content/en/docs/Concepts/principles.en.md new file mode 100644 index 0000000000..45e574b90a --- /dev/null +++ b/site/content/en/docs/Concepts/principles.en.md @@ -0,0 +1,28 @@ +--- +title: "Principles" +date: 2019-06-18T15:31:58+08:00 +--- + +The primary goal of minikube is to make it simple to run Kubernetes locally, for day-to-day development workflows and learning purposes. Here are the guiding principles for minikube, in rough priority order: + +1. User-friendly and accessible +2. Inclusive and community-driven +3. Cross-platform +4. Support all Kubernetes features +5. High-fidelity +6. Compatible with all supported Kubernetes releases +7. Support for all Kubernetes-friendly container runtimes +8. Stable and easy to debug + +Here are some specific minikube features that align with our goal: + +* Single command setup and teardown UX +* Support for local storage, networking, auto-scaling, load balancing, etc. +* Unified UX across operating systems +* Minimal dependencies on third party software +* Minimal resource overhead + +## Non-Goals + +* Simplifying Kubernetes production deployment experience +* Supporting all possible deployment configurations of Kubernetes like various types of storage, networking, etc. diff --git a/site/content/en/docs/Contributing/_index.md b/site/content/en/docs/Contributing/_index.md new file mode 100644 index 0000000000..7aef294ff1 --- /dev/null +++ b/site/content/en/docs/Contributing/_index.md @@ -0,0 +1,7 @@ +--- +title: "Contributing" +linkTitle: "Contributing" +weight: 10 +description: > + How to contribute to minikube +--- diff --git a/site/content/en/docs/Contributing/addons.en.md b/site/content/en/docs/Contributing/addons.en.md new file mode 100644 index 0000000000..150482fd3c --- /dev/null +++ b/site/content/en/docs/Contributing/addons.en.md @@ -0,0 +1,64 @@ +--- +title: "Addons" +date: 2019-07-31 +weight: 4 +description: > + How to develop minikube addons +--- + +## Adding a New Addon + +To add a new addon to minikube the following steps are required: + +* For the new addon's .yaml file(s): + * Put the required .yaml files for the addon in the `minikube/deploy/addons` directory. + * Add the `kubernetes.io/minikube-addons: ` label to each piece of the addon (ReplicationController, Service, etc.) + * Also, the `addonmanager.kubernetes.io/mode` annotation is needed so that your resources are picked up by the `addon-manager`. + * In order to have `minikube addons open ` work properly, the `kubernetes.io/minikube-addons-endpoint: ` label must be added to the appropriate endpoint service (what the user would want to open/interact with). This service must be of type NodePort. + +* To add the addon into minikube commands/VM: + * Add the addon with appropriate fields filled into the `Addon` dictionary, see this [commit](https://github.com/kubernetes/minikube/commit/41998bdad0a5543d6b15b86b0862233e3204fab6#diff-e2da306d559e3f019987acc38431a3e8R133) and example. + + ```go + // cmd/minikube/cmd/config/config.go + var settings = []Setting{ + ..., + // add other addon setting + { + name: "efk", + set: SetBool, + validations: []setFn{IsValidAddon}, + callbacks: []setFn{EnableOrDisableAddon}, + }, + } + ``` + + * Add the addon to settings list, see this [commit](https://github.com/kubernetes/minikube/commit/41998bdad0a5543d6b15b86b0862233e3204fab6#diff-07ad0c54f98b231e68537d908a214659R89) and example. + + ```go + // pkg/minikube/assets/addons.go + var Addons = map[string]*Addon{ + ..., + // add other addon asset + "efk": NewAddon([]*BinAsset{ + MustBinAsset( + "deploy/addons/efk/efk-configmap.yaml", + constants.AddonsPath, + "efk-configmap.yaml", + "0640"), + MustBinAsset( + "deploy/addons/efk/efk-rc.yaml", + constants.AddonsPath, + "efk-rc.yaml", + "0640"), + MustBinAsset( + "deploy/addons/efk/efk-svc.yaml", + constants.AddonsPath, + "efk-svc.yaml", + "0640"), + }, false, "efk"), + } + ``` + +* Rebuild minikube using make out/minikube. This will put the addon's .yaml binary files into the minikube binary using go-bindata. +* Test addon using `minikube addons enable ` command to start service. diff --git a/site/content/en/docs/Contributing/building.en.md b/site/content/en/docs/Contributing/building.en.md new file mode 100644 index 0000000000..e2fa9a42d6 --- /dev/null +++ b/site/content/en/docs/Contributing/building.en.md @@ -0,0 +1,130 @@ +--- +title: "Building minikube" +date: 2019-07-31 +weight: 4 +description: > + Building minikube +--- + +This guide covers both building the minikube binary and the ISO. + +## Prerequisites + +* A recent Go distribution (>=1.12) +* If you are on Windows, you'll need Docker to be installed. +* 4GB of RAM + +Additionally, if you are on Fedora, you will need to install `glibc-static`: + +```shell +sudo dnf install -y glibc-static +``` + +## Downloading the source + +```shell +git clone https://github.com/kubernetes/minikube.git +cd minikube +``` + +## Building the binary + +```shell +make +``` + +Alternatively, you may cross-compile to/from different operating systems: + +```shell +MINIKUBE_BUILD_IN_DOCKER=y make cross +``` + +The resulting binaries for each platform will be located in the `out/` subdirectory. + +## Using a source-built minikube binary + +Start the cluster using your built minikube with: + +```shell +./out/minikube start +``` + +## Building the ISO + +The minikube ISO is booted by each hypervisor to provide a stable minimal Linux environment to start Kubernetes from. It is based on coreboot, uses systemd, and includes all necessary container runtimes and hypervisor guest drivers. + +### Prerequisites + +See the above requirements for building the minikube binary. Additionally, you will need: + +```shell +sudo apt-get install build-essential gnupg2 p7zip-full git wget cpio python \ + unzip bc gcc-multilib automake libtool locales +``` +### Build instructions + +```shell +$ make buildroot-image +$ make out/minikube.iso +``` + +The build will occur inside a docker container. If you want to do this on +baremetal, replace `make out/minikube.iso` with `IN_DOCKER=1 make out/minikube.iso`. +The bootable ISO image will be available in `out/minikube.iso`. + +### Using a local ISO image + +```shell +$ ./out/minikube start --iso-url=file://$(pwd)/out/minikube.iso +``` + +### Modifying buildroot components + +To change which Linux userland components are included by the guest VM, use this to modify the buildroot configuration: + +```shell +cd out/buildroot +make menuconfig +make +``` + +To save these configuration changes, execute: + +```shell +make savedefconfig +``` + +The changes will be reflected in the `minikube-iso/configs/minikube_defconfig` file. + +### Adding kernel modules + +To make kernel configuration changes and save them, execute: + +```shell +$ make linux-menuconfig +``` + +This will open the kernel configuration menu, and then save your changes to our +iso directory after they've been selected. + +### Adding third-party packages + +To add your own package to the minikube ISO, create a package directory under `iso/minikube-iso/package`. This directory will require at least 3 files: + +`.mk` - A Makefile describing how to download the source code and build the program +`.hash` - Checksums to verify the downloaded source code +`Config.in` - buildroot configuration. + +For a relatively simple example to start with, you may want to reference the `podman` package. + +## Continuous Integration Builds + +We publish CI builds of minikube, built at every Pull Request. Builds are available at (substitute in the relevant PR number): + +- +- +- + +We also publish CI builds of minikube-iso, built at every Pull Request that touches deploy/iso/minikube-iso. Builds are available at: + +- diff --git a/site/content/en/docs/Contributing/drivers.en.md b/site/content/en/docs/Contributing/drivers.en.md new file mode 100644 index 0000000000..954c373874 --- /dev/null +++ b/site/content/en/docs/Contributing/drivers.en.md @@ -0,0 +1,108 @@ +--- +title: "Drivers" +date: 2019-07-31 +weight: 4 +description: > + How to create a new VM Driver +--- + +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=`. + +## Creating a new driver + +See https://github.com/machine-drivers, the fork where all new docker-machine drivers are located. + +## Builtin vs External Drivers + +Most drivers are built-in: they are included into minikube as a code dependency, so no further +installation is required. There are two primary cases you may want to use an external driver: + +- The driver has a code dependency which minikube should not rely on due to platform incompatibilities (kvm2) or licensing +- The driver needs to run with elevated permissions (hyperkit) + +External drivers are instantiated by executing a command `docker-machine-driver-`, which begins an RPC server which minikube will talk to. + +### Integrating a driver + +The integration process is effectively 3 steps. + +1. Create a driver shim within `k8s.io/minikube/pkg/minikube/drivers` + - Add Go build tag for the supported operating systems + - Define the driver metadata to register in `DriverDef` +2. Add import in `pkg/minikube/cluster/default_drivers.go` so that the driver may be included by the minikube build process. + +### The driver shim + +The primary duty of the driver shim is to register a VM driver with minikube, and translate minikube VM hardware configuration into a format that the driver understands. + +### Registering your driver + +The godoc of registry is available here: + +[DriverDef](https://godoc.org/k8s.io/minikube/pkg/minikube/registry#DriverDef) is the main +struct to define a driver metadata. Essentially, you need to define 4 things at most, which is +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 + +- Builtin: `true` if the driver should be builtin to minikube (preferred). `false` otherwise. + +- ConfigCreator: how to translate a minikube config to driver config. The driver config will be persistent +on your `$USER/.minikube` directory. Most likely the driver config is the driver itself. + +- DriverCreator: Only needed when driver is builtin, to instantiate the driver instance. + + +## Integration example: vmwarefusion + +All drivers are located in `k8s.io/minikube/pkg/minikube/drivers`. Take `vmwarefusion` as an example: + +```golang +// +build darwin + +package vmwarefusion + +import ( + "github.com/docker/machine/drivers/vmwarefusion" + "github.com/docker/machine/libmachine/drivers" + cfg "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/registry" +) + +func init() { + registry.Register(registry.DriverDef{ + Name: "vmwarefusion", + Builtin: true, + ConfigCreator: createVMwareFusionHost, + DriverCreator: func() drivers.Driver { + return vmwarefusion.NewDriver("", "") + }, + }) +} + +func createVMwareFusionHost(config cfg.MachineConfig) interface{} { + d := vmwarefusion.NewDriver(cfg.GetMachineName(), constants.GetMinipath()).(*vmwarefusion.Driver) + d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) + d.Memory = config.Memory + d.CPU = config.CPUs + d.DiskSize = config.DiskSize + d.SSHPort = 22 + d.ISO = d.ResolveStorePath("boot2docker.iso") + return d +} +``` + +- Within the `init()` function, register a `DriverDef` in registry. Specify the metadata in the `DriverDef`. As mentioned +earlier, it's builtin, so you also need to specify `DriverCreator` to tell minikube how to create a `drivers.Driver`. +- Another important thing is `vmwarefusion` only runs on MacOS. You need to add a build tag on top so it only +runs on MacOS, so that the releases on Windows and Linux won't have this driver in registry. +- Last but not least, import the driver in `pkg/minikube/cluster/default_drivers.go` to include it in build. + + + +Any Questions: please ping your friend [@anfernee](https://github.com/anfernee) or the #minikube Slack channel. + diff --git a/site/content/en/docs/Contributing/releasing.en.md b/site/content/en/docs/Contributing/releasing.en.md new file mode 100644 index 0000000000..90e498f321 --- /dev/null +++ b/site/content/en/docs/Contributing/releasing.en.md @@ -0,0 +1,115 @@ +--- +title: "Releasing" +date: 2019-07-31 +weight: 9 +description: > + How to release minikube +--- + +## Preparation + +* Announce release intent on #minikube +* Pause merge requests so that they are not accidentally left out of the ISO or release notes + +## Build a new ISO + +Major releases always get a new ISO. Minor bugfixes may or may not require it: check for changes in the `deploy/iso` folder. +To check, run `git log -- deploy/iso` from the root directory and see if there has been a commit since the most recent release. + +Note: you can build the ISO using the `hack/jenkins/build_iso.sh` script locally. + +* Navigate to the minikube ISO jenkins job +* Ensure that you are logged in (top right) +* Click "▶️ Build with Parameters" (left) +* For `ISO_VERSION`, type in the intended release version (same as the minikube binary's version) +* For `ISO_BUCKET`, type in `minikube/iso` +* Click *Build* + +The build will take roughly 50 minutes. + +## Update Makefile + +Edit the minikube `Makefile`, updating the version number values at the top: + +* `VERSION_MAJOR`, `VERSION_MINOR`, `VERSION_BUILD` as necessary +* `ISO_VERSION` - defaults to MAJOR.MINOR.0 - update if point release requires a new ISO to be built. + +Make sure the integration tests run against this PR, once the new ISO is built. + +## Ad-Hoc testing of other platforms + +If there are supported platforms which do not have functioning Jenkins workers (Windows), you may use the following to build a sanity check: + +```shell +env BUILD_IN_DOCKER=y make cross checksum +``` + +## Send out Makefile PR + +Once submitted, HEAD will use the new ISO. Please pay attention to test failures, as this is our integration test across platforms. If there are known acceptable failures, please add a PR comment linking to the appropriate issue. + +## Update Release Notes + +Run the following script to update the release notes: + +```shell +hack/release_notes.sh +``` + +Merge the output into CHANGELOG.md. See [PR#3175](https://github.com/kubernetes/minikube/pull/3175) as an example. Then get the PR submitted. + +## Tag the Release + +```shell +sh hack/tag_release.sh 1.. +``` + +## Build the Release + +This step uses the git tag to publish new binaries to GCS and create a github release: + +* Navigate to the minikube "Release" jenkins job +* Ensure that you are logged in (top right) +* Click "▶️ Build with Parameters" (left) +* `VERSION_MAJOR`, `VERSION_MINOR`, and `VERSION_BUILD` should reflect the values in your Makefile +* For `ISO_SHA256`, run: `gsutil cat gs://minikube/iso/minikube-v.iso.sha256` +* Click *Build* + +## Check the release logs + +After job completion, click "Console Output" to verify that the release completed without errors. This is typically where one will see brew automation fail, for instance. + +## Check releases.json + +This file is used for auto-update notifications, but is not active until releases.json is copied to GCS. + +minikube-bot will send out a PR to update the release checksums at the top of `deploy/minikube/releases.json`. You should merge this PR. + +## Package managers which include minikube + +These are downstream packages that are being maintained by others and how to upgrade them to make sure they have the latest versions + +| Package Manager | URL | TODO | +| --------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Arch Linux AUR | | "Flag as package out-of-date" | +| Brew Cask | | The release job creates a new PR in [Homebrew/homebrew-cask](https://github.com/Homebrew/homebrew-cask) with an updated version and SHA256, double check that it's created. | + +WARNING: The Brew cask automation is error-prone. please ensure that a PR was created. + +## Verification + +Verify release checksums by running `make check-release` + +## Update docs + +If there are major changes, please send a PR to update + +## Announce + +Please mention the new release https://github.com/kubernetes/minikube/blob/master/README.md + +Other places: + +- #minikube on Slack +- minikube-dev, minikube-users mailing list +- Twitter (optional!) diff --git a/site/content/en/docs/Contributing/roadmap.en.md b/site/content/en/docs/Contributing/roadmap.en.md new file mode 100644 index 0000000000..b938681a32 --- /dev/null +++ b/site/content/en/docs/Contributing/roadmap.en.md @@ -0,0 +1,56 @@ +--- +title: "Roadmap" +date: 2019-07-31 +weight: 4 +description: > + 2019 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) + +Please send a PR to suggest any improvements to it. + +## (#1) User-friendly and accessible + +- [ ] Creation of a user-centric minikube website for installation & documentation +- [ ] Localized output to 5+ written languages +- [x] Make minikube usable in environments with challenging connectivity requirements +- [ ] Support lightweight deployment methods for environments where VM's are impractical +- [x] Add offline support + +## (#2) Inclusive and community-driven + +- [x] Increase community involvement in planning and decision making +- [ ] Make the continuous integration and release infrastructure publicly available +- [x] Double the number of active maintainers + +## (#3) Cross-platform + +- [ ] Simplified installation process across all supported platforms +- [ ] Users should never need to separately install supporting binaries + +## (#4) Support all Kubernetes features + +- [ ] Add multi-node support + +## (#5) High-fidelity + +- [ ] Reduce guest VM overhead by 50% +- [x] Disable swap in the guest VM + +## (#6) Compatible with all supported Kubernetes releases + +- [x] Continuous Integration testing across all supported Kubernetes releases +- [ ] Automatic PR generation for updating the default Kubernetes release minikube uses + +## (#7) Support for all Kubernetes-friendly container runtimes + +- [x] Run all integration tests across all supported container runtimes +- [ ] Support for Kata Containers (help wanted!) + +## (#8) Stable and easy to debug + +- [x] Pre-flight error checks for common connectivity and configuration errors +- [ ] Improve the `minikube status` command so that it can diagnose common issues +- [ ] Mark all features not covered by continuous integration as `experimental` +- [x] Stabilize and improve profiles support (AKA multi-cluster) diff --git a/site/content/en/docs/Contributing/testing.en.md b/site/content/en/docs/Contributing/testing.en.md new file mode 100644 index 0000000000..9f3d35ec88 --- /dev/null +++ b/site/content/en/docs/Contributing/testing.en.md @@ -0,0 +1,59 @@ +--- +title: "Testing" +date: 2019-07-31 +weight: 4 +description: > + How to run tests +--- + +### Unit Tests + +Unit tests are run on Travis before code is merged. To run as part of a development cycle: + +```shell +make test +``` + +### Integration Tests + +Integration tests are currently run manually. +To run them, build the binary and run the tests: + +```shell +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 + ``` + +### Conformance Tests + +These are Kubernetes tests that run against an arbitrary cluster and exercise a wide range of Kubernetes features. +You can run these against minikube by following these steps: + +* Clone the Kubernetes repo somewhere on your system. +* Run `make quick-release` in the k8s repo. +* Start up a minikube cluster with: `minikube start`. +* Set following two environment variables: + +```shell +export KUBECONFIG=$HOME/.kube/config +export KUBERNETES_CONFORMANCE_TEST=y +``` + +* Run the tests (from the k8s repo): + +```shell +go run hack/e2e.go -v --test --test_args="--ginkgo.focus=\[Conformance\]" --check-version-skew=false +``` + +To run a specific conformance test, you can use the `ginkgo.focus` flag to filter the set using a regular expression. +The `hack/e2e.go` wrapper and the `e2e.sh` wrappers have a little trouble with quoting spaces though, so use the `\s` regular expression character instead. +For example, to run the test `should update annotations on modification [Conformance]`, use following command: + +```shell +go run hack/e2e.go -v --test --test_args="--ginkgo.focus=should\supdate\sannotations\son\smodification" --check-version-skew=false +``` diff --git a/site/content/en/docs/Examples/_index.md b/site/content/en/docs/Examples/_index.md new file mode 100755 index 0000000000..6798cc43c9 --- /dev/null +++ b/site/content/en/docs/Examples/_index.md @@ -0,0 +1,41 @@ + +--- +title: "Examples" +linkTitle: "Examples" +weight: 3 +date: 2017-01-05 +description: > + See minikube in action! +--- + +Start a cluster by running: + +`minikube start` + +Access the Kubernetes Dashboard running within the minikube cluster: + +`minikube dashboard` + +Once started, you can interact with your cluster using `kubectl`, just like any other Kubernetes cluster. For instance, starting a server: + +`kubectl run hello-minikube --image=k8s.gcr.io/echoserver:1.4 --port=8080` + +Exposing a service as a NodePort + +`kubectl expose deployment hello-minikube --type=NodePort` + +minikube makes it easy to open this exposed endpoint in your browser: + +`minikube service hello-minikube` + +Start a second local cluster: + +`minikube start -p cluster2` + +Stop your local cluster: + +`minikube stop` + +Delete your local cluster: + +`minikube delete` diff --git a/site/content/en/docs/Getting started/_index.md b/site/content/en/docs/Getting started/_index.md new file mode 100644 index 0000000000..2347037978 --- /dev/null +++ b/site/content/en/docs/Getting started/_index.md @@ -0,0 +1,7 @@ +--- +title: "Getting Started" +linkTitle: "Getting Started" +weight: 2 +description: > + How to install and start minikube. +--- diff --git a/site/content/en/docs/Getting started/_post_install.md b/site/content/en/docs/Getting started/_post_install.md new file mode 100644 index 0000000000..77c44f6f94 --- /dev/null +++ b/site/content/en/docs/Getting started/_post_install.md @@ -0,0 +1,20 @@ +### Getting to know Kubernetes + +Once started, you can use any regular Kubernetes command to interact with your minikube cluster. For example, you can see the pod states by running: + +```shell + kubectl get po -A +``` + +### Increasing memory allocation + +minikube only allocates 2GB of RAM by default, which is only enough for trivial deployments. For larger +deployments, increase the memory allocation using the `--memory` flag, or make the setting persistent using: + +```shell +minikube config set memory 4096 +``` + +### Where to go next? + +Visit the [examples](/docs/examples) page to get an idea of what you can do with minikube. diff --git a/site/content/en/docs/Getting started/_virtualbox.md b/site/content/en/docs/Getting started/_virtualbox.md new file mode 100644 index 0000000000..9f2c51c55f --- /dev/null +++ b/site/content/en/docs/Getting started/_virtualbox.md @@ -0,0 +1,7 @@ +Download and install the latest version of VirtualBox from https://www.virtualbox.org/ + +Once installed, start minikube: + +```shell +minikube start +``` diff --git a/site/content/en/docs/Getting started/linux.md b/site/content/en/docs/Getting started/linux.md new file mode 100644 index 0000000000..a4b421aea4 --- /dev/null +++ b/site/content/en/docs/Getting started/linux.md @@ -0,0 +1,115 @@ +--- +title: "Linux" +linkTitle: "Linux" +weight: 1 +--- + +## Installation + +{{% tabs %}} +{{% tab "Direct" %}} + +Download and install minikube to /usr/local/bin: + +```shell + curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \ + && sudo install minikube-linux-amd64 /usr/local/bin/minikube +``` +{{% /tab %}} +{{% tab "Debian/Ubuntu (deb)" %}} + +Download and install minikube: + +```shell +curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_{{< latest >}}.deb \ + && sudo dpkg -i minikube_{{< latest >}}.deb + ``` + +{{% /tab %}} + +{{% tab "Fedora/Red Hat (rpm)" %}} + +Download and install minikube: + +```shell +curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-{{< latest >}}.rpm \ + && sudo rpm -ivh minikube-{{< latest >}}.rpm + ``` + +{{% /tab %}} +{{% /tabs %}} + +## Hypervisor Setup + +Verify that your system has virtualization support enabled: + +```shell +egrep -q 'vmx|svm' /proc/cpuinfo && echo yes || echo no +``` + +If the above command outputs "no": + +- If you are running within a VM, your hypervisor does not allow nested virtualization. You will need to use the *None (bare-metal)* driver +- If you are running on a physical machine, ensure that your BIOS has hardware virtualization enabled + +{{% tabs %}} + +{{% tab "VirtualBox" %}} +{{% readfile file="/docs/Getting started/_virtualbox.md" %}} +{{% /tab %}} +{{% tab "KVM" %}} + +The KVM driver requires libvirt and qemu-kvm to be installed: + +- Debian or Ubuntu 18.x: `sudo apt install libvirt-clients libvirt-daemon-system qemu-kvm` +- Ubuntu 16.x or older: `sudo apt install libvirt-bin libvirt-daemon-system qemu-kvm` +- Fedora/CentOS/RHEL: `sudo yum install libvirt libvirt-daemon-kvm qemu-kvm` +- openSUSE/SLES: `sudo zypper install libvirt qemu-kvm` + +Additionally, The KVM driver requires an additional binary to be installed: + +```shell + curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-kvm2 \ + && sudo install docker-machine-driver-kvm2 /usr/local/bin/ +``` + +### Validate libvirt + +Before trying minikube, assert that libvirt is in a healthy state: + +```shell +virt-host-validate +``` + +If you see any errors, stop now and consult your distributions documentation on configuring libvirt. + +### Using the kvm2 driver + +```shell +minikube start --vm-driver=kvm2 +``` +To make kvm2 the default for future invocations, run: + +```shell +minikube config set vm-driver kvm2 +``` + +{{% /tab %}} +{{% tab "None (bare-metal)" %}} + +If you are already running minikube from inside a VM, it is possible to skip the creation of an additional VM layer by using the `none` driver. +This mode does come with additional requirements: + +- docker +- systemd +- sudo access + +```shell +sudo minikube start --vm-driver=none +``` + +Please see the [docs/reference/drivers/none](none driver) documentation for more information. +{{% /tab %}} +{{% /tabs %}} + +{{% readfile file="/docs/Getting started/_post_install.md" %}} diff --git a/site/content/en/docs/Getting started/macos.md b/site/content/en/docs/Getting started/macos.md new file mode 100644 index 0000000000..938b63e7c9 --- /dev/null +++ b/site/content/en/docs/Getting started/macos.md @@ -0,0 +1,111 @@ +--- +title: "macOS" +linkTitle: "macOS" +weight: 2 +--- + +### Prerequisites + +* macOS 10.12 (Sierra) +* A hypervisor such as Hyperkit, Parallels, VirtualBox, or VMware Fusion + +### Installation + +{{% tabs %}} +{{% tab "Brew" %}} + +If you have the [Brew Package Manager](https://brew.sh/) installed, this will download and install minikube to /usr/local/bin: + +```shell +brew install minikube +``` + +{{% /tab %}} +{{% tab "Direct" %}} + +Download and install minikube to /usr/local/bin: + +```shell +curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 \ + && sudo install minikube-darwin-amd64 /usr/local/bin/minikube +``` +{{% /tab %}} + +{{% /tabs %}} + +## Hypervisor Setup + +{{% tabs %}} +{{% tab "VirtualBox" %}} +{{% readfile file="/docs/Getting started/_virtualbox.md" %}} +{{% /tab %}} +{{% tab "Hyperkit" %}} + +The easiest way to install hyperkit is using the [Brew Package Manager](https://brew.sh/): + +```shell +brew install hyperkit +``` + +To use minikube and hyperkit reliably, please download and install our improved fork of the driver: + +```shell +curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit \ + && sudo install docker-machine-driver-hyperkit /usr/local/bin/ +``` + +This driver requires root privileges to create and destroy network interfaces: + +```shell +sudo chown root:wheel /usr/local/bin +docker-machine-driver-hyperkit \ +&& sudo chmod u+s /usr/local/bin/docker-machine-driver-hyperkit +``` + +### Using the hyperkit driver + +```shell +minikube start --vm-driver=hyperkit +``` + +To make hyperkit the default for future invocations: + +```shell +minikube config set vm-driver hyperkit +``` + +{{% /tab %}} + +{{% tab "Parallels" %}} + +Start minikube with Parallels support using: + +```shell +minikube start --vm-driver=parallels +``` + +To make parallels the default for future invocations: + +```shell +minikube config set vm-driver parallels +``` +{{% /tab %}} + +{{% tab "VMware Fusion" %}} + +Start minikube with VMware Fusion support using: + +```shell +minikube start --vm-driver=vmwarefusion +``` + +To make vmwarefusion the default for future invocations: + +```shell +minikube config set vm-driver vmwarefusion +``` +{{% /tab %}} + +{{% /tabs %}} + +{{% readfile file="/docs/Getting started/_post_install.md" %}} \ No newline at end of file diff --git a/site/content/en/docs/Getting started/windows.md b/site/content/en/docs/Getting started/windows.md new file mode 100644 index 0000000000..e01a6662e5 --- /dev/null +++ b/site/content/en/docs/Getting started/windows.md @@ -0,0 +1,80 @@ +--- +title: "Windows" +linkTitle: "Windows" +weight: 3 +--- + +### Prerequisites + + * Windows 8 or above + * A hypervisor, such as Hyper-V or VirtualBox + * Hardware virtualization support must be enabled in BIOS + * 4GB of RAM + +### Installation + +{{% tabs %}} +{{% tab "Direct" %}} +Download and run the [installer](https://storage.googleapis.com/minikube/releases/latest/minikube-installer.exe) +{{% /tab %}} + +{{% tab "Chocolatey" %}} + +If you have the [Chocolatey Package Manager](https://chocolatey.org/) installed, you can install minikube if run as an Administrator: + +```shell +choco install minikube +``` + +After it has installed, close the current CLI session and reopen it. minikube should have been added to your path automatically. +{{% /tab %}} +{{% /tabs %}} + + +## Hypervisor Setup + +To check if virtualization is supported, run the following command on your Windows terminal or command prompt. + +```shell +systeminfo +``` +If you see the following output, virtualization is supported: + +```shell +Hyper-V Requirements: VM Monitor Mode Extensions: Yes + Virtualization Enabled In Firmware: Yes + Second Level Address Translation: Yes + Data Execution Prevention Available: Yes +``` + +If you see the following output, your system already has a Hypervisor installed and you can skip the next step. + +``` +Hyper-V Requirements: A hypervisor has been detected. + Features required for Hyper-V will not be displayed. +``` + +{{% tabs %}} +{{% tab "VirtualBox" %}} +{{% readfile file="/docs/Getting started/_virtualbox.md" %}} +{{% /tab %}} +{{% tab "Hyper-V" %}} + +If Hyper-V is active, you can start minikube with Hyper-V support using: + +```shell +minikube start --vm-driver=hyperv +``` + +NOTE: If this fails due to networking issues, see the [Hyper-V driver documentation](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyper-v-driver) for further instructions. + +To make hyperv the default for future invocations: + +```shell +minikube config set vm-driver hyperv +``` + +{{% /tab %}} +{{% /tabs %}} + +{{% readfile file="/docs/Getting started/_post_install.md" %}} \ No newline at end of file diff --git a/site/content/en/docs/Overview/_index.md b/site/content/en/docs/Overview/_index.md new file mode 100644 index 0000000000..e173cd330e --- /dev/null +++ b/site/content/en/docs/Overview/_index.md @@ -0,0 +1,50 @@ +--- +title: "Overview" +linkTitle: "Overview" +weight: 1 +description: > + What is it? +--- + +minikube implements a local Kubernetes cluster on macOS, Linux, and Windows. + +minikube's [primary goals](https://github.com/kubernetes/minikube/blob/master/docs/contributors/principles.md) are to be the best tool for local Kubernetes application development and to support all Kubernetes features that fit. + +minikube runs the latest stable release of Kubernetes, with support for standard Kubernetes features like: + +* [LoadBalancer](https://github.com/kubernetes/minikube/blob/master/docs/tunnel.md) - using `minikube tunnel` +* Multi-cluster - using `minikube start -p ` +* NodePorts - using `minikube service` +* [Persistent Volumes](https://github.com/kubernetes/minikube/blob/master/docs/persistent_volumes.md) +* Ingress +* RBAC +* [Dashboard](https://github.com/kubernetes/minikube/blob/master/docs/dashboard.md) - `minikube dashboard` +* [Container runtimes](https://github.com/kubernetes/minikube/blob/master/docs/alternative_runtimes.md) - `start --container-runtime` +* [Configure apiserver and kubelet options](https://github.com/kubernetes/minikube/blob/master/docs/configuring_kubernetes.md) via command-line flags + +As well as developer-friendly features: + +* [Addons](https://github.com/kubernetes/minikube/blob/master/docs/addons.md) - a marketplace for developers to share configurations for running services on minikube +* [GPU support](https://github.com/kubernetes/minikube/blob/master/docs/gpu.md) - for machine learning +* [Filesystem mounts](https://github.com/kubernetes/minikube/blob/master/docs/host_folder_mount.md) +* Automatic failure analysis + +## Why do I want it? + +If you would like to develop Kubernetes applications: + +* locally +* offline +* using the latest version of Kubernetes + +Then minikube is for you. + +* **What is it good for?** Developing local Kubernetes applications +* **What is it not good for?** Production deployments of Kubernetes applications +* **What is it *not yet* good for?** Environments which do not allow VM's + +## Where should I go next? + +* [Getting Started](/getting-started/): Get started with minikube +* [Examples](/examples/): Check out some minikube examples! +* \ No newline at end of file diff --git a/site/content/en/docs/Reference/Commands/_index.md b/site/content/en/docs/Reference/Commands/_index.md new file mode 100644 index 0000000000..3d61dcedbd --- /dev/null +++ b/site/content/en/docs/Reference/Commands/_index.md @@ -0,0 +1,13 @@ +--- +title: "Commands" +linkTitle: "Command" +weight: 8 +date: 2017-01-05 +description: > + minikube command reference +--- + +{{% pageinfo %}} +This is a placeholder page where command documentation will go. +{{% /pageinfo %}} + diff --git a/site/content/en/docs/Reference/Drivers/_index.md b/site/content/en/docs/Reference/Drivers/_index.md new file mode 100644 index 0000000000..f3ca3ba2fb --- /dev/null +++ b/site/content/en/docs/Reference/Drivers/_index.md @@ -0,0 +1,8 @@ +--- +title: "Drivers" +linkTitle: "Drivers" +weight: 8 +date: 2017-01-05 +description: > + Configuring minikube drivers +--- diff --git a/site/content/en/docs/Reference/Networking/_index.md b/site/content/en/docs/Reference/Networking/_index.md new file mode 100644 index 0000000000..1e2effb540 --- /dev/null +++ b/site/content/en/docs/Reference/Networking/_index.md @@ -0,0 +1,10 @@ +--- +title: "Networking" +linkTitle: "Networking" +weight: 8 +date: 2017-01-05 +description: > + Configuring networking with minikube +--- + +Since minikube runs all services within a VM environment, networking gets pretty complicated. Networking is both a popular topic among power users, and the most common cause for failed minikube deployments. diff --git a/site/content/en/docs/Reference/Networking/accessing-host-resources.md b/site/content/en/docs/Reference/Networking/accessing-host-resources.md new file mode 100644 index 0000000000..421eb0afb5 --- /dev/null +++ b/site/content/en/docs/Reference/Networking/accessing-host-resources.md @@ -0,0 +1,40 @@ +--- +title: "Accessing host resources" +date: 2017-01-05 +weight: 2 +description: > + How to access host resources from a pod +--- + +{{% pageinfo %}} +This has only been tested on VirtualBox and Hyperkit. Instructions may differ for other VM drivers. +{{% /pageinfo %}} + +### Prerequisites + +The service running on your host must either be bound to all IP's (0.0.0.0) and interfaces, or to the IP and interface your VM is bridged against. If the service is bound only to localhost (127.0.0.1), this will not work. + +### Getting the bridge IP + +To access a resource, such as a MySQL service running on your host, from inside of a pod, the key information you need is the correct target IP to use. + +```shell +minikube ssh "route -n | grep ^0.0.0.0 | awk '{ print \$2 }'" +``` + +Example output: + +``` +10.0.2.2 +``` + +This is the IP your pods can connect to in order to access services running on the host. + +### Validating connectivity + +```shell +minikube ssh +telnet +``` + +If you press enter, you may see an interesting string or error message pop up. This means that the connection is working. diff --git a/site/content/en/docs/Reference/_index.md b/site/content/en/docs/Reference/_index.md new file mode 100644 index 0000000000..e8d2e3f801 --- /dev/null +++ b/site/content/en/docs/Reference/_index.md @@ -0,0 +1,13 @@ +--- +title: "Reference" +linkTitle: "Reference" +weight: 9 +description: > + Low level reference docs +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +If your project has an API, configuration, or other reference - anything that users need to look up that’s at an even lower level than a single task - put (or link to it) here. diff --git a/site/content/en/docs/Tasks/_index.md b/site/content/en/docs/Tasks/_index.md new file mode 100755 index 0000000000..3d0254cb19 --- /dev/null +++ b/site/content/en/docs/Tasks/_index.md @@ -0,0 +1,23 @@ +--- +title: "Core Tasks" +linkTitle: "Core Tasks" +weight: 6 +date: 2017-01-05 +description: > + What can you do with minikube? +--- + +{{% pageinfo %}} +This is a placeholder page that shows you how to use this template site. +{{% /pageinfo %}} + +Think about your project’s features and use cases. Use these to choose your core tasks. Each granular use case (enable x, configure y) should have a corresponding tasks page or tasks page section. Users should be able to quickly refer to your core tasks when they need to find out how to do one specific thing, rather than having to look for the instructions in a bigger tutorial or example. Think of your tasks pages as a cookbook with different procedures your users can combine to create something more substantial. + +You can give each task a page, or you can group related tasks together in a page, such as tasks related to a particular feature. As well as grouping related tasks in single pages, you can also group task pages in nested folders with an index page as an overview, as seen in this example site. Or if you have a small docset like the [Docsy User Guide](https://docsy.dev/docs/) with no Tutorials or Concepts pages, consider adding your feature-specific pages at the top level of your docs rather than in a Tasks section. + +Each task should give the user + +* The prerequisites for this task, if any (this can be specified at the top of a multi-task page if they're the same for all the page's tasks. "All these tasks assume that you understand....and that you have already...."). +* What this task accomplishes. +* Instructions for the task. If it involves editing a file, running a command, or writing code, provide code-formatted example snippets to show the user what to do! If there are multiple steps, provide them as a numbered list. +* If appropriate, links to related concept, tutorial, or example pages. diff --git a/site/content/en/docs/Tasks/addons.md b/site/content/en/docs/Tasks/addons.md new file mode 100644 index 0000000000..037dfbb3ce --- /dev/null +++ b/site/content/en/docs/Tasks/addons.md @@ -0,0 +1,72 @@ +--- +title: "Addons" +date: 2019-07-31 +weight: 4 +description: > + Using addons +--- + +minikube has a set of built-in addons that, when enabled, can be used within Kubernetes. + +## Available addons + +* [Kubernetes Dashboard](https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dashboard) +* [Heapster](https://github.com/kubernetes/heapster): [Troubleshooting Guide](https://github.com/kubernetes/heapster/blob/master/docs/influxdb.md) Note:You will need to login to Grafana as admin/admin in order to access the console +* [EFK](https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/fluentd-elasticsearch) +* [Registry](https://github.com/kubernetes/minikube/tree/master/deploy/addons/registry) +* [Registry Credentials](https://github.com/upmc-enterprises/registry-creds) +* [Ingress](https://github.com/kubernetes/ingress-nginx) +* [Freshpod](https://github.com/GoogleCloudPlatform/freshpod) +* [nvidia-driver-installer](https://github.com/GoogleCloudPlatform/container-engine-accelerators/tree/master/nvidia-driver-installer/minikube) +* [nvidia-gpu-device-plugin](https://github.com/GoogleCloudPlatform/container-engine-accelerators/tree/master/cmd/nvidia_gpu) +* [logviewer](https://github.com/ivans3/minikube-log-viewer) +* [gvisor](../deploy/addons/gvisor/README.md) +* [storage-provisioner-gluster](../deploy/addons/storage-provisioner-gluster/README.md) + +## Listing available addons + +```shell +minikube addons list +``` + +Example output: + +``` +- registry: disabled +- registry-creds: disabled +- freshpod: disabled +- addon-manager: enabled +- dashboard: enabled +- heapster: disabled +- efk: disabled +- ingress: disabled +- default-storageclass: enabled +- storage-provisioner: enabled +- storage-provisioner-gluster: disabled +- nvidia-driver-installer: disabled +- nvidia-gpu-device-plugin: disabled +``` + +## Enabling an addon + +```shell +minikube addons enable +``` + +## Interacting with an addon + +For addons that expose a browser endpoint, use: + +```shell +minikube addons open +``` + +## Disabling an addon + +```shell +minikube addons disable +``` + +## Custom Addons + +If you would like to have minikube properly start/restart custom addons, place the addon(s) you wish to be launched with minikube in the `.minikube/addons` directory. Addons in this folder will be moved to the minikube VM and launched each time minikube is started/restarted. diff --git a/site/content/en/docs/Tasks/mount.md b/site/content/en/docs/Tasks/mount.md new file mode 100644 index 0000000000..409e0aca59 --- /dev/null +++ b/site/content/en/docs/Tasks/mount.md @@ -0,0 +1,59 @@ +--- +title: "Filesystem mounts" +date: 2017-01-05 +weight: 4 +description: > + How to mount a host directory into the VM +--- + +It is possible to mount directories from the host into the guest using the `mount` subcommand: + +``` +minikube mount : +``` + +For example, this would mount your home directory to appear as /host within the minikube VM: + +``` +minikube mount $HOME:/host +``` + +This directory may then be referenced from a Kubernetes manifest, for example: + +```shell +{ + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "ubuntu" + }, + "spec": { + "containers": [ + { + "name": "ubuntu", + "image": "ubuntu:18.04", + "args": [ + "bash" + ], + "stdin": true, + "stdinOnce": true, + "tty": true, + "workingDir": "/host", + "volumeMounts": [{ + "mountPath": "/host", + "name": "host-mount" + }] + } + ], + "volumes": [ + { + "name": "host-mount", + "hostPath": { + "path": "/host" + } + } + ] + } +} +``` + diff --git a/site/content/en/docs/Tutorials/_index.md b/site/content/en/docs/Tutorials/_index.md new file mode 100755 index 0000000000..b58fb2a184 --- /dev/null +++ b/site/content/en/docs/Tutorials/_index.md @@ -0,0 +1,11 @@ + +--- +title: "Tutorials" +linkTitle: "Tutorials" +weight: 8 +date: 2017-01-04 +description: > + Contributed end-to-end tutorials using minikube +--- + +Tutorials are **complete worked examples** made up of **multiple tasks** that guide the user through a relatively simple but realistic scenario: building an application that uses some of your project’s features, for example. If you have already created some Examples for your project you can base Tutorials on them. diff --git a/site/content/en/docs/Tutorials/multi-bear.md b/site/content/en/docs/Tutorials/multi-bear.md new file mode 100644 index 0000000000..2b6a33483c --- /dev/null +++ b/site/content/en/docs/Tutorials/multi-bear.md @@ -0,0 +1,238 @@ +--- +title: "Multi-Bear Domicile Setup" +date: 2017-01-05 +weight: 4 +description: > + A short lead descripton about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/site/content/en/docs/Tutorials/tutorial2.md b/site/content/en/docs/Tutorials/tutorial2.md new file mode 100644 index 0000000000..b6afc4e503 --- /dev/null +++ b/site/content/en/docs/Tutorials/tutorial2.md @@ -0,0 +1,238 @@ +--- +title: "Another Tutorial" +date: 2017-01-05 +weight: 5 +description: > + A short lead descripton about this content page. It can be **bold** or _italic_ and can be split over multiple paragraphs. +--- + +{{% pageinfo %}} +This is a placeholder page. Replace it with your own content. +{{% /pageinfo %}} + +Text can be **bold**, _italic_, or ~~strikethrough~~. [Links](https://gohugo.io) should be blue with no underlines (unless hovered over). + +There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde. + +90's four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps **kale chips**. + +> There should be no margin above this first sentence. +> +> Blockquotes should be a lighter gray with a border along the left side in the secondary color. +> +> There should be no margin below this final sentence. + +## First Header 2 + +This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier **craft beer**. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven't heard of them copper mug, crucifix green juice vape *single-origin coffee* brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay! + +Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque. + +On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width. + +Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. **I love this life we live in**. + + +## Second Header 2 + +> This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### Header 3 + +``` +This is a code block following a header. +``` + +Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan. + +#### Header 4 + +* This is an unordered list following a header. +* This is an unordered list following a header. +* This is an unordered list following a header. + +##### Header 5 + +1. This is an ordered list following a header. +2. This is an ordered list following a header. +3. This is an ordered list following a header. + +###### Header 6 + +| What | Follows | +|-----------|-----------------| +| A table | A header | +| A table | A header | +| A table | A header | + +---------------- + +There's a horizontal rule above and below this. + +---------------- + +Here is an unordered list: + +* Liverpool F.C. +* Chelsea F.C. +* Manchester United F.C. + +And an ordered list: + +1. Michael Brecker +2. Seamus Blake +3. Branford Marsalis + +And an unordered task list: + +- [x] Create a Hugo theme +- [x] Add task lists to it +- [ ] Take a vacation + +And a "mixed" task list: + +- [ ] Pack bags +- ? +- [ ] Travel! + +And a nested list: + +* Jackson 5 + * Michael + * Tito + * Jackie + * Marlon + * Jermaine +* TMNT + * Leonardo + * Michelangelo + * Donatello + * Raphael + +Definition lists can be used with Markdown syntax. Definition headers are bold. + +Name +: Godzilla + +Born +: 1952 + +Birthplace +: Japan + +Color +: Green + + +---------------- + +Tables should have bold headings and alternating shaded rows. + +| Artist | Album | Year | +|-------------------|-----------------|------| +| Michael Jackson | Thriller | 1982 | +| Prince | Purple Rain | 1984 | +| Beastie Boys | License to Ill | 1986 | + +If a table is too wide, it should scroll horizontally. + +| Artist | Album | Year | Label | Awards | Songs | +|-------------------|-----------------|------|-------------|----------|-----------| +| Michael Jackson | Thriller | 1982 | Epic Records | Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical | Wanna Be Startin' Somethin', Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life | +| Prince | Purple Rain | 1984 | Warner Brothers Records | Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal | Let's Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I'm a Star, Purple Rain | +| Beastie Boys | License to Ill | 1986 | Mercury Records | noawardsbutthistablecelliswide | Rhymin & Stealin, The New Style, She's Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill | + +---------------- + +Code snippets like `var foo = "bar";` can be shown inline. + +Also, `this should vertically align` ~~`with this`~~ ~~and this~~. + +Code can also be shown in a block element. + +``` +foo := "bar"; +bar := "foo"; +``` + +Code can also use syntax highlighting. + +```go +func main() { + input := `var foo = "bar";` + + lexer := lexers.Get("javascript") + iterator, _ := lexer.Tokenise(nil, input) + style := styles.Get("github") + formatter := html.New(html.WithLineNumbers()) + + var buff bytes.Buffer + formatter.Format(&buff, style, iterator) + + fmt.Println(buff.String()) +} +``` + +``` +Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this. +``` + +Inline code inside table cells should still be distinguishable. + +| Language | Code | +|-------------|--------------------| +| Javascript | `var foo = "bar";` | +| Ruby | `foo = "bar"{` | + +---------------- + +Small images should be shown at their actual size. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/240px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +Large images should always scale down and fit in the content container. + +![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg/1024px-Picea_abies_shoot_with_buds%2C_Sogndal%2C_Norway.jpg) + +_The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA._ + + +## Components + +### Alerts + +{{< alert >}}This is an alert.{{< /alert >}} +{{< alert title="Note" >}}This is an alert with a title.{{< /alert >}} +{{% alert title="Note" %}}This is an alert with a title and **Markdown**.{{% /alert %}} +{{< alert color="success" >}}This is a successful alert.{{< /alert >}} +{{< alert color="warning" >}}This is a warning.{{< /alert >}} +{{< alert color="warning" title="Warning" >}}This is a warning with a title.{{< /alert >}} + + +## Another Heading + +Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong. + +### This Document + +Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam *eripitur*? Sitim noceat signa *probat quidem*. Sua longis *fugatis* quidem genae. + + +### Pixel Count + +Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic. + +### Contact Info + +Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly. + + +### External Links + +Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat. + + + +``` +This is the final element on the page and there should be no margin below this. +``` diff --git a/site/content/en/docs/_index.md b/site/content/en/docs/_index.md new file mode 100755 index 0000000000..f285e090f8 --- /dev/null +++ b/site/content/en/docs/_index.md @@ -0,0 +1,11 @@ + +--- +title: "Documentation" +linkTitle: "Documentation" +weight: 20 +menu: + main: + weight: 20 +--- +This section is where the user documentation for minikube lives - all the information that users need to understand and successfully use minikube. + diff --git a/site/content/en/featured-background.jpg b/site/content/en/featured-background.jpg new file mode 100644 index 0000000000..c737f0ff94 Binary files /dev/null and b/site/content/en/featured-background.jpg differ diff --git a/site/content/en/logo.png b/site/content/en/logo.png new file mode 100644 index 0000000000..d21b6b2a2b Binary files /dev/null and b/site/content/en/logo.png differ diff --git a/site/content/en/search.md b/site/content/en/search.md new file mode 100644 index 0000000000..e3690fd5a8 --- /dev/null +++ b/site/content/en/search.md @@ -0,0 +1,6 @@ +--- +title: Search Results +layout: search + +--- + diff --git a/site/content/en/start.jpg b/site/content/en/start.jpg new file mode 100644 index 0000000000..1ee9cc3e6c Binary files /dev/null and b/site/content/en/start.jpg differ diff --git a/site/layouts/partials/hooks/body-end.html b/site/layouts/partials/hooks/body-end.html new file mode 100644 index 0000000000..afcc7b8b61 --- /dev/null +++ b/site/layouts/partials/hooks/body-end.html @@ -0,0 +1,2 @@ + + diff --git a/site/layouts/partials/hooks/head-end.html b/site/layouts/partials/hooks/head-end.html new file mode 100644 index 0000000000..c28153d11c --- /dev/null +++ b/site/layouts/partials/hooks/head-end.html @@ -0,0 +1,3 @@ + + + diff --git a/site/layouts/shortcodes/latest.html b/site/layouts/shortcodes/latest.html new file mode 100644 index 0000000000..dc746b6c22 --- /dev/null +++ b/site/layouts/shortcodes/latest.html @@ -0,0 +1 @@ +{{ $.Site.Params.latest_release }} \ No newline at end of file diff --git a/site/layouts/shortcodes/tab.html b/site/layouts/shortcodes/tab.html new file mode 100644 index 0000000000..30be2cad9e --- /dev/null +++ b/site/layouts/shortcodes/tab.html @@ -0,0 +1,3 @@ +
+ {{ .Inner }} +
diff --git a/site/layouts/shortcodes/tabs.html b/site/layouts/shortcodes/tabs.html new file mode 100644 index 0000000000..bee221a334 --- /dev/null +++ b/site/layouts/shortcodes/tabs.html @@ -0,0 +1,4 @@ +
+ +
{{ .Inner }}
+
diff --git a/site/package-lock.json b/site/package-lock.json new file mode 100644 index 0000000000..0cb1933f78 --- /dev/null +++ b/site/package-lock.json @@ -0,0 +1,2821 @@ +{ + "name": "tech-doc-hugo", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "9.4.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.4.6.tgz", + "integrity": "sha512-Yp51mevbOEdxDUy5WjiKtpQaecqYq9OqZSL04rSoCiry7Tc5I9FEyo3bfxiTJc1DfHeKwSFCUYbBAiOQ2VGfiw==", + "dev": true, + "requires": { + "browserslist": "^4.4.1", + "caniuse-lite": "^1.0.30000929", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.13", + "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browserslist": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.1.tgz", + "integrity": "sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000929", + "electron-to-chromium": "^1.3.103", + "node-releases": "^1.1.3" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30000932", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz", + "integrity": "sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "dev": true, + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "dev": true + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.108", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.108.tgz", + "integrity": "sha512-/QI4hMpAh48a1Sea6PALGv+kuVne9A2EWGd8HrWHMdYhIzGtbhVVHh6heL5fAzGaDnZuPyrlWJRl8WPm4RyiQQ==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-extra": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", + "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "merge2": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "node-releases": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.3.tgz", + "integrity": "sha512-6VrvH7z6jqqNFY200kdB6HdzkgM96Oaj9v3dqGfgp6mF+cHmU4wyQKZ2/WPDRVoR0Jz9KqbamaBN0ZhdUaysUQ==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-5.0.1.tgz", + "integrity": "sha512-yrvWl8axFdiXlJuVQRIHM4qskvl0F4/fWUUIYyYo0RV6lOdB0Vcyt8Rv7lBvtwVuNa0pClz88LgxzT4ZzC7UWA==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "chokidar": "^2.0.0", + "dependency-graph": "^0.7.0", + "fs-extra": "^5.0.0", + "get-stdin": "^6.0.0", + "globby": "^8.0.0", + "postcss": "^6.0.1", + "postcss-load-config": "^1.1.0", + "postcss-reporter": "^5.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "yargs": "^11.0.0" + } + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0", + "postcss-load-options": "^1.2.0", + "postcss-load-plugins": "^2.3.0" + } + }, + "postcss-load-options": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", + "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0" + } + }, + "postcss-load-plugins": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", + "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.1", + "object-assign": "^4.1.0" + } + }, + "postcss-reporter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-5.0.0.tgz", + "integrity": "sha512-rBkDbaHAu5uywbCR2XE8a25tats3xSOsGNx6mppK6Q9kSFGKc/FyAzfci+fWM2l+K402p1D0pNcfDGxeje5IKg==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "lodash": "^4.17.4", + "log-symbols": "^2.0.0", + "postcss": "^6.0.8" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } +} diff --git a/site/package.json b/site/package.json new file mode 100644 index 0000000000..ce3b9af2e4 --- /dev/null +++ b/site/package.json @@ -0,0 +1,24 @@ +{ + "name": "tech-doc-hugo", + "version": "0.0.1", + "description": "Hugo theme for technical documentation.", + "main": "none.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/bep/tech-doc-hugo.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/bep/tech-doc-hugo/issues" + }, + "homepage": "https://github.com/bep/tech-doc-hugo#readme", + "dependencies": {}, + "devDependencies": { + "autoprefixer": "^9.4.6", + "postcss-cli": "^5.0.1" + } +} diff --git a/site/resources/_gen/assets/scss/scss/style.scss_5ad6f408b0e3e473c748aac88af0ea18.content b/site/resources/_gen/assets/scss/scss/style.scss_5ad6f408b0e3e473c748aac88af0ea18.content deleted file mode 100644 index 00ca65cf31..0000000000 --- a/site/resources/_gen/assets/scss/scss/style.scss_5ad6f408b0e3e473c748aac88af0ea18.content +++ /dev/null @@ -1,6151 +0,0 @@ -@charset "UTF-8"; -@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Lora:400,700|Roboto+Mono:300,400"); -*, -*::before, -*::after { - box-sizing: border-box; } - -html { - font-family: sans-serif; - line-height: 1.15; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - -ms-overflow-style: scrollbar; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } - -@-ms-viewport { - width: device-width; } - -article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section { - display: block; } - -body { - margin: 0; - font-family: "Roboto", Arial, sans-serif, -apple-system; - font-size: 1rem; - font-weight: 400; - line-height: 1.4; - color: #212529; - text-align: left; - background-color: #fff; } - -[tabindex="-1"]:focus { - outline: 0 !important; } - -hr { - box-sizing: content-box; - height: 0; - overflow: visible; } - -h1, h2, h3, h4, h5, h6 { - margin-top: 0; - margin-bottom: 0.5rem; } - -p { - margin-top: 0; - margin-bottom: 1rem; } - -abbr[title], -abbr[data-original-title] { - text-decoration: underline; - text-decoration: underline dotted; - cursor: help; - border-bottom: 0; } - -address { - margin-bottom: 1rem; - font-style: normal; - line-height: inherit; } - -ol, -ul, -dl { - margin-top: 0; - margin-bottom: 1rem; } - -ol ol, -ul ul, -ol ul, -ul ol { - margin-bottom: 0; } - -dt { - font-weight: 700; } - -dd { - margin-bottom: .5rem; - margin-left: 0; } - -blockquote { - margin: 0 0 1rem; } - -dfn { - font-style: italic; } - -b, -strong { - font-weight: bolder; } - -small { - font-size: 80%; } - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; } - -sub { - bottom: -.25em; } - -sup { - top: -.5em; } - -a { - color: #1de9b6; - text-decoration: none; - background-color: transparent; - -webkit-text-decoration-skip: objects; } - a:hover { - color: #7af2d4; - text-decoration: underline; } - -a:not([href]):not([tabindex]) { - color: inherit; - text-decoration: none; } - a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { - color: inherit; - text-decoration: none; } - a:not([href]):not([tabindex]):focus { - outline: 0; } - -pre, -code, -kbd, -samp { - font-family: monospace, monospace; - font-size: 1em; } - -pre { - margin-top: 0; - margin-bottom: 1rem; - overflow: auto; - -ms-overflow-style: scrollbar; } - -figure { - margin: 0 0 1rem; } - -img { - vertical-align: middle; - border-style: none; } - -svg:not(:root) { - overflow: hidden; } - -table { - border-collapse: collapse; } - -caption { - padding-top: 0.75rem; - padding-bottom: 0.75rem; - color: #6c757d; - text-align: left; - caption-side: bottom; } - -th { - text-align: inherit; } - -label { - display: inline-block; - margin-bottom: .5rem; } - -button { - border-radius: 0; } - -button:focus { - outline: 1px dotted; - outline: 5px auto -webkit-focus-ring-color; } - -input, -button, -select, -optgroup, -textarea { - margin: 0; - font-family: inherit; - font-size: inherit; - line-height: inherit; } - -button, -input { - overflow: visible; } - -button, -select { - text-transform: none; } - -button, -html [type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; } - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - padding: 0; - border-style: none; } - -input[type="radio"], -input[type="checkbox"] { - box-sizing: border-box; - padding: 0; } - -input[type="date"], -input[type="time"], -input[type="datetime-local"], -input[type="month"] { - -webkit-appearance: listbox; } - -textarea { - overflow: auto; - resize: vertical; } - -fieldset { - min-width: 0; - padding: 0; - margin: 0; - border: 0; } - -legend { - display: block; - width: 100%; - max-width: 100%; - padding: 0; - margin-bottom: .5rem; - font-size: 1.5rem; - line-height: inherit; - color: inherit; - white-space: normal; } - -progress { - vertical-align: baseline; } - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; } - -[type="search"] { - outline-offset: -2px; - -webkit-appearance: none; } - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; } - -::-webkit-file-upload-button { - font: inherit; - -webkit-appearance: button; } - -output { - display: inline-block; } - -summary { - display: list-item; - cursor: pointer; } - -template { - display: none; } - -[hidden] { - display: none !important; } - -.align-baseline { - vertical-align: baseline !important; } - -.align-top { - vertical-align: top !important; } - -.align-middle { - vertical-align: middle !important; } - -.align-bottom { - vertical-align: bottom !important; } - -.align-text-bottom { - vertical-align: text-bottom !important; } - -.align-text-top { - vertical-align: text-top !important; } - -.bg-primary { - background-color: #1de9b6 !important; } - -a.bg-primary:hover, a.bg-primary:focus, -button.bg-primary:hover, -button.bg-primary:focus { - background-color: #13c095 !important; } - -.bg-secondary { - background-color: #ffca28 !important; } - -a.bg-secondary:hover, a.bg-secondary:focus, -button.bg-secondary:hover, -button.bg-secondary:focus { - background-color: #f4b800 !important; } - -.bg-success { - background-color: #28a745 !important; } - -a.bg-success:hover, a.bg-success:focus, -button.bg-success:hover, -button.bg-success:focus { - background-color: #1e7e34 !important; } - -.bg-info { - background-color: #17a2b8 !important; } - -a.bg-info:hover, a.bg-info:focus, -button.bg-info:hover, -button.bg-info:focus { - background-color: #117a8b !important; } - -.bg-warning { - background-color: #ffc107 !important; } - -a.bg-warning:hover, a.bg-warning:focus, -button.bg-warning:hover, -button.bg-warning:focus { - background-color: #d39e00 !important; } - -.bg-danger { - background-color: #dc3545 !important; } - -a.bg-danger:hover, a.bg-danger:focus, -button.bg-danger:hover, -button.bg-danger:focus { - background-color: #bd2130 !important; } - -.bg-light { - background-color: #f8f9fa !important; } - -a.bg-light:hover, a.bg-light:focus, -button.bg-light:hover, -button.bg-light:focus { - background-color: #dae0e5 !important; } - -.bg-dark { - background-color: #343a40 !important; } - -a.bg-dark:hover, a.bg-dark:focus, -button.bg-dark:hover, -button.bg-dark:focus { - background-color: #1d2124 !important; } - -.bg-white { - background-color: #fff !important; } - -.bg-transparent { - background-color: transparent !important; } - -.border { - border: 1px solid #dee2e6 !important; } - -.border-top { - border-top: 1px solid #dee2e6 !important; } - -.border-right { - border-right: 1px solid #dee2e6 !important; } - -.border-bottom { - border-bottom: 1px solid #dee2e6 !important; } - -.border-left { - border-left: 1px solid #dee2e6 !important; } - -.border-0 { - border: 0 !important; } - -.border-top-0 { - border-top: 0 !important; } - -.border-right-0 { - border-right: 0 !important; } - -.border-bottom-0 { - border-bottom: 0 !important; } - -.border-left-0 { - border-left: 0 !important; } - -.border-primary { - border-color: #1de9b6 !important; } - -.border-secondary { - border-color: #ffca28 !important; } - -.border-success { - border-color: #28a745 !important; } - -.border-info { - border-color: #17a2b8 !important; } - -.border-warning { - border-color: #ffc107 !important; } - -.border-danger { - border-color: #dc3545 !important; } - -.border-light { - border-color: #f8f9fa !important; } - -.border-dark { - border-color: #343a40 !important; } - -.border-white { - border-color: #fff !important; } - -.rounded { - border-radius: 0.25rem !important; } - -.rounded-top { - border-top-left-radius: 0.25rem !important; - border-top-right-radius: 0.25rem !important; } - -.rounded-right { - border-top-right-radius: 0.25rem !important; - border-bottom-right-radius: 0.25rem !important; } - -.rounded-bottom { - border-bottom-right-radius: 0.25rem !important; - border-bottom-left-radius: 0.25rem !important; } - -.rounded-left { - border-top-left-radius: 0.25rem !important; - border-bottom-left-radius: 0.25rem !important; } - -.rounded-circle { - border-radius: 50% !important; } - -.rounded-0 { - border-radius: 0 !important; } - -.clearfix::after { - display: block; - clear: both; - content: ""; } - -.d-none { - display: none !important; } - -.d-inline { - display: inline !important; } - -.d-inline-block { - display: inline-block !important; } - -.d-block { - display: block !important; } - -.d-table { - display: table !important; } - -.d-table-row { - display: table-row !important; } - -.d-table-cell { - display: table-cell !important; } - -.d-flex { - display: flex !important; } - -.d-inline-flex { - display: inline-flex !important; } - -@media (min-width: 576px) { - .d-sm-none { - display: none !important; } - .d-sm-inline { - display: inline !important; } - .d-sm-inline-block { - display: inline-block !important; } - .d-sm-block { - display: block !important; } - .d-sm-table { - display: table !important; } - .d-sm-table-row { - display: table-row !important; } - .d-sm-table-cell { - display: table-cell !important; } - .d-sm-flex { - display: flex !important; } - .d-sm-inline-flex { - display: inline-flex !important; } } - -@media (min-width: 768px) { - .d-md-none { - display: none !important; } - .d-md-inline { - display: inline !important; } - .d-md-inline-block { - display: inline-block !important; } - .d-md-block { - display: block !important; } - .d-md-table { - display: table !important; } - .d-md-table-row { - display: table-row !important; } - .d-md-table-cell { - display: table-cell !important; } - .d-md-flex { - display: flex !important; } - .d-md-inline-flex { - display: inline-flex !important; } } - -@media (min-width: 992px) { - .d-lg-none { - display: none !important; } - .d-lg-inline { - display: inline !important; } - .d-lg-inline-block { - display: inline-block !important; } - .d-lg-block { - display: block !important; } - .d-lg-table { - display: table !important; } - .d-lg-table-row { - display: table-row !important; } - .d-lg-table-cell { - display: table-cell !important; } - .d-lg-flex { - display: flex !important; } - .d-lg-inline-flex { - display: inline-flex !important; } } - -@media (min-width: 1300px) { - .d-xl-none { - display: none !important; } - .d-xl-inline { - display: inline !important; } - .d-xl-inline-block { - display: inline-block !important; } - .d-xl-block { - display: block !important; } - .d-xl-table { - display: table !important; } - .d-xl-table-row { - display: table-row !important; } - .d-xl-table-cell { - display: table-cell !important; } - .d-xl-flex { - display: flex !important; } - .d-xl-inline-flex { - display: inline-flex !important; } } - -@media print { - .d-print-none { - display: none !important; } - .d-print-inline { - display: inline !important; } - .d-print-inline-block { - display: inline-block !important; } - .d-print-block { - display: block !important; } - .d-print-table { - display: table !important; } - .d-print-table-row { - display: table-row !important; } - .d-print-table-cell { - display: table-cell !important; } - .d-print-flex { - display: flex !important; } - .d-print-inline-flex { - display: inline-flex !important; } } - -.embed-responsive { - position: relative; - display: block; - width: 100%; - padding: 0; - overflow: hidden; } - .embed-responsive::before { - display: block; - content: ""; } - .embed-responsive .embed-responsive-item, - .embed-responsive iframe, - .embed-responsive embed, - .embed-responsive object, - .embed-responsive video { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - border: 0; } - -.embed-responsive-21by9::before { - padding-top: 42.85714286%; } - -.embed-responsive-16by9::before { - padding-top: 56.25%; } - -.embed-responsive-4by3::before { - padding-top: 75%; } - -.embed-responsive-1by1::before { - padding-top: 100%; } - -.flex-row { - flex-direction: row !important; } - -.flex-column { - flex-direction: column !important; } - -.flex-row-reverse { - flex-direction: row-reverse !important; } - -.flex-column-reverse { - flex-direction: column-reverse !important; } - -.flex-wrap { - flex-wrap: wrap !important; } - -.flex-nowrap { - flex-wrap: nowrap !important; } - -.flex-wrap-reverse { - flex-wrap: wrap-reverse !important; } - -.justify-content-start { - justify-content: flex-start !important; } - -.justify-content-end { - justify-content: flex-end !important; } - -.justify-content-center { - justify-content: center !important; } - -.justify-content-between { - justify-content: space-between !important; } - -.justify-content-around { - justify-content: space-around !important; } - -.align-items-start { - align-items: flex-start !important; } - -.align-items-end { - align-items: flex-end !important; } - -.align-items-center { - align-items: center !important; } - -.align-items-baseline { - align-items: baseline !important; } - -.align-items-stretch { - align-items: stretch !important; } - -.align-content-start { - align-content: flex-start !important; } - -.align-content-end { - align-content: flex-end !important; } - -.align-content-center { - align-content: center !important; } - -.align-content-between { - align-content: space-between !important; } - -.align-content-around { - align-content: space-around !important; } - -.align-content-stretch { - align-content: stretch !important; } - -.align-self-auto { - align-self: auto !important; } - -.align-self-start { - align-self: flex-start !important; } - -.align-self-end { - align-self: flex-end !important; } - -.align-self-center { - align-self: center !important; } - -.align-self-baseline { - align-self: baseline !important; } - -.align-self-stretch { - align-self: stretch !important; } - -@media (min-width: 576px) { - .flex-sm-row { - flex-direction: row !important; } - .flex-sm-column { - flex-direction: column !important; } - .flex-sm-row-reverse { - flex-direction: row-reverse !important; } - .flex-sm-column-reverse { - flex-direction: column-reverse !important; } - .flex-sm-wrap { - flex-wrap: wrap !important; } - .flex-sm-nowrap { - flex-wrap: nowrap !important; } - .flex-sm-wrap-reverse { - flex-wrap: wrap-reverse !important; } - .justify-content-sm-start { - justify-content: flex-start !important; } - .justify-content-sm-end { - justify-content: flex-end !important; } - .justify-content-sm-center { - justify-content: center !important; } - .justify-content-sm-between { - justify-content: space-between !important; } - .justify-content-sm-around { - justify-content: space-around !important; } - .align-items-sm-start { - align-items: flex-start !important; } - .align-items-sm-end { - align-items: flex-end !important; } - .align-items-sm-center { - align-items: center !important; } - .align-items-sm-baseline { - align-items: baseline !important; } - .align-items-sm-stretch { - align-items: stretch !important; } - .align-content-sm-start { - align-content: flex-start !important; } - .align-content-sm-end { - align-content: flex-end !important; } - .align-content-sm-center { - align-content: center !important; } - .align-content-sm-between { - align-content: space-between !important; } - .align-content-sm-around { - align-content: space-around !important; } - .align-content-sm-stretch { - align-content: stretch !important; } - .align-self-sm-auto { - align-self: auto !important; } - .align-self-sm-start { - align-self: flex-start !important; } - .align-self-sm-end { - align-self: flex-end !important; } - .align-self-sm-center { - align-self: center !important; } - .align-self-sm-baseline { - align-self: baseline !important; } - .align-self-sm-stretch { - align-self: stretch !important; } } - -@media (min-width: 768px) { - .flex-md-row { - flex-direction: row !important; } - .flex-md-column { - flex-direction: column !important; } - .flex-md-row-reverse { - flex-direction: row-reverse !important; } - .flex-md-column-reverse { - flex-direction: column-reverse !important; } - .flex-md-wrap { - flex-wrap: wrap !important; } - .flex-md-nowrap { - flex-wrap: nowrap !important; } - .flex-md-wrap-reverse { - flex-wrap: wrap-reverse !important; } - .justify-content-md-start { - justify-content: flex-start !important; } - .justify-content-md-end { - justify-content: flex-end !important; } - .justify-content-md-center { - justify-content: center !important; } - .justify-content-md-between { - justify-content: space-between !important; } - .justify-content-md-around { - justify-content: space-around !important; } - .align-items-md-start { - align-items: flex-start !important; } - .align-items-md-end { - align-items: flex-end !important; } - .align-items-md-center { - align-items: center !important; } - .align-items-md-baseline { - align-items: baseline !important; } - .align-items-md-stretch { - align-items: stretch !important; } - .align-content-md-start { - align-content: flex-start !important; } - .align-content-md-end { - align-content: flex-end !important; } - .align-content-md-center { - align-content: center !important; } - .align-content-md-between { - align-content: space-between !important; } - .align-content-md-around { - align-content: space-around !important; } - .align-content-md-stretch { - align-content: stretch !important; } - .align-self-md-auto { - align-self: auto !important; } - .align-self-md-start { - align-self: flex-start !important; } - .align-self-md-end { - align-self: flex-end !important; } - .align-self-md-center { - align-self: center !important; } - .align-self-md-baseline { - align-self: baseline !important; } - .align-self-md-stretch { - align-self: stretch !important; } } - -@media (min-width: 992px) { - .flex-lg-row { - flex-direction: row !important; } - .flex-lg-column { - flex-direction: column !important; } - .flex-lg-row-reverse { - flex-direction: row-reverse !important; } - .flex-lg-column-reverse { - flex-direction: column-reverse !important; } - .flex-lg-wrap { - flex-wrap: wrap !important; } - .flex-lg-nowrap { - flex-wrap: nowrap !important; } - .flex-lg-wrap-reverse { - flex-wrap: wrap-reverse !important; } - .justify-content-lg-start { - justify-content: flex-start !important; } - .justify-content-lg-end { - justify-content: flex-end !important; } - .justify-content-lg-center { - justify-content: center !important; } - .justify-content-lg-between { - justify-content: space-between !important; } - .justify-content-lg-around { - justify-content: space-around !important; } - .align-items-lg-start { - align-items: flex-start !important; } - .align-items-lg-end { - align-items: flex-end !important; } - .align-items-lg-center { - align-items: center !important; } - .align-items-lg-baseline { - align-items: baseline !important; } - .align-items-lg-stretch { - align-items: stretch !important; } - .align-content-lg-start { - align-content: flex-start !important; } - .align-content-lg-end { - align-content: flex-end !important; } - .align-content-lg-center { - align-content: center !important; } - .align-content-lg-between { - align-content: space-between !important; } - .align-content-lg-around { - align-content: space-around !important; } - .align-content-lg-stretch { - align-content: stretch !important; } - .align-self-lg-auto { - align-self: auto !important; } - .align-self-lg-start { - align-self: flex-start !important; } - .align-self-lg-end { - align-self: flex-end !important; } - .align-self-lg-center { - align-self: center !important; } - .align-self-lg-baseline { - align-self: baseline !important; } - .align-self-lg-stretch { - align-self: stretch !important; } } - -@media (min-width: 1300px) { - .flex-xl-row { - flex-direction: row !important; } - .flex-xl-column { - flex-direction: column !important; } - .flex-xl-row-reverse { - flex-direction: row-reverse !important; } - .flex-xl-column-reverse { - flex-direction: column-reverse !important; } - .flex-xl-wrap { - flex-wrap: wrap !important; } - .flex-xl-nowrap { - flex-wrap: nowrap !important; } - .flex-xl-wrap-reverse { - flex-wrap: wrap-reverse !important; } - .justify-content-xl-start { - justify-content: flex-start !important; } - .justify-content-xl-end { - justify-content: flex-end !important; } - .justify-content-xl-center { - justify-content: center !important; } - .justify-content-xl-between { - justify-content: space-between !important; } - .justify-content-xl-around { - justify-content: space-around !important; } - .align-items-xl-start { - align-items: flex-start !important; } - .align-items-xl-end { - align-items: flex-end !important; } - .align-items-xl-center { - align-items: center !important; } - .align-items-xl-baseline { - align-items: baseline !important; } - .align-items-xl-stretch { - align-items: stretch !important; } - .align-content-xl-start { - align-content: flex-start !important; } - .align-content-xl-end { - align-content: flex-end !important; } - .align-content-xl-center { - align-content: center !important; } - .align-content-xl-between { - align-content: space-between !important; } - .align-content-xl-around { - align-content: space-around !important; } - .align-content-xl-stretch { - align-content: stretch !important; } - .align-self-xl-auto { - align-self: auto !important; } - .align-self-xl-start { - align-self: flex-start !important; } - .align-self-xl-end { - align-self: flex-end !important; } - .align-self-xl-center { - align-self: center !important; } - .align-self-xl-baseline { - align-self: baseline !important; } - .align-self-xl-stretch { - align-self: stretch !important; } } - -.float-left { - float: left !important; } - -.float-right { - float: right !important; } - -.float-none { - float: none !important; } - -@media (min-width: 576px) { - .float-sm-left { - float: left !important; } - .float-sm-right { - float: right !important; } - .float-sm-none { - float: none !important; } } - -@media (min-width: 768px) { - .float-md-left { - float: left !important; } - .float-md-right { - float: right !important; } - .float-md-none { - float: none !important; } } - -@media (min-width: 992px) { - .float-lg-left { - float: left !important; } - .float-lg-right { - float: right !important; } - .float-lg-none { - float: none !important; } } - -@media (min-width: 1300px) { - .float-xl-left { - float: left !important; } - .float-xl-right { - float: right !important; } - .float-xl-none { - float: none !important; } } - -.position-static { - position: static !important; } - -.position-relative { - position: relative !important; } - -.position-absolute { - position: absolute !important; } - -.position-fixed { - position: fixed !important; } - -.position-sticky { - position: sticky !important; } - -.fixed-top { - position: fixed; - top: 0; - right: 0; - left: 0; - z-index: 1030; } - -.fixed-bottom { - position: fixed; - right: 0; - bottom: 0; - left: 0; - z-index: 1030; } - -@supports (position: sticky) { - .sticky-top { - position: sticky; - top: 0; - z-index: 1020; } } - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - clip-path: inset(50%); - border: 0; } - -.sr-only-focusable:active, .sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - overflow: visible; - clip: auto; - white-space: normal; - clip-path: none; } - -.w-25 { - width: 25% !important; } - -.w-50 { - width: 50% !important; } - -.w-75 { - width: 75% !important; } - -.w-100 { - width: 100% !important; } - -.h-25 { - height: 25% !important; } - -.h-50 { - height: 50% !important; } - -.h-75 { - height: 75% !important; } - -.h-100 { - height: 100% !important; } - -.mw-100 { - max-width: 100% !important; } - -.mh-100 { - max-height: 100% !important; } - -.m-0 { - margin: 0 !important; } - -.mt-0, -.my-0 { - margin-top: 0 !important; } - -.mr-0, -.mx-0 { - margin-right: 0 !important; } - -.mb-0, -.my-0 { - margin-bottom: 0 !important; } - -.ml-0, -.mx-0 { - margin-left: 0 !important; } - -.m-1 { - margin: 10px !important; } - -.mt-1, -.my-1 { - margin-top: 10px !important; } - -.mr-1, -.mx-1 { - margin-right: 10px !important; } - -.mb-1, -.my-1 { - margin-bottom: 10px !important; } - -.ml-1, -.mx-1 { - margin-left: 10px !important; } - -.m-2 { - margin: 20px !important; } - -.mt-2, -.my-2 { - margin-top: 20px !important; } - -.mr-2, -.mx-2 { - margin-right: 20px !important; } - -.mb-2, -.my-2 { - margin-bottom: 20px !important; } - -.ml-2, -.mx-2 { - margin-left: 20px !important; } - -.m-3 { - margin: 30px !important; } - -.mt-3, -.my-3 { - margin-top: 30px !important; } - -.mr-3, -.mx-3 { - margin-right: 30px !important; } - -.mb-3, -.my-3 { - margin-bottom: 30px !important; } - -.ml-3, -.mx-3 { - margin-left: 30px !important; } - -.m-4 { - margin: 40px !important; } - -.mt-4, -.my-4 { - margin-top: 40px !important; } - -.mr-4, -.mx-4 { - margin-right: 40px !important; } - -.mb-4, -.my-4 { - margin-bottom: 40px !important; } - -.ml-4, -.mx-4 { - margin-left: 40px !important; } - -.m-5 { - margin: 50px !important; } - -.mt-5, -.my-5 { - margin-top: 50px !important; } - -.mr-5, -.mx-5 { - margin-right: 50px !important; } - -.mb-5, -.my-5 { - margin-bottom: 50px !important; } - -.ml-5, -.mx-5 { - margin-left: 50px !important; } - -.m-6 { - margin: 60px !important; } - -.mt-6, -.my-6 { - margin-top: 60px !important; } - -.mr-6, -.mx-6 { - margin-right: 60px !important; } - -.mb-6, -.my-6 { - margin-bottom: 60px !important; } - -.ml-6, -.mx-6 { - margin-left: 60px !important; } - -.m-7 { - margin: 70px !important; } - -.mt-7, -.my-7 { - margin-top: 70px !important; } - -.mr-7, -.mx-7 { - margin-right: 70px !important; } - -.mb-7, -.my-7 { - margin-bottom: 70px !important; } - -.ml-7, -.mx-7 { - margin-left: 70px !important; } - -.m-8 { - margin: 80px !important; } - -.mt-8, -.my-8 { - margin-top: 80px !important; } - -.mr-8, -.mx-8 { - margin-right: 80px !important; } - -.mb-8, -.my-8 { - margin-bottom: 80px !important; } - -.ml-8, -.mx-8 { - margin-left: 80px !important; } - -.m-9 { - margin: 90px !important; } - -.mt-9, -.my-9 { - margin-top: 90px !important; } - -.mr-9, -.mx-9 { - margin-right: 90px !important; } - -.mb-9, -.my-9 { - margin-bottom: 90px !important; } - -.ml-9, -.mx-9 { - margin-left: 90px !important; } - -.m-10 { - margin: 100px !important; } - -.mt-10, -.my-10 { - margin-top: 100px !important; } - -.mr-10, -.mx-10 { - margin-right: 100px !important; } - -.mb-10, -.my-10 { - margin-bottom: 100px !important; } - -.ml-10, -.mx-10 { - margin-left: 100px !important; } - -.m-11 { - margin: 110px !important; } - -.mt-11, -.my-11 { - margin-top: 110px !important; } - -.mr-11, -.mx-11 { - margin-right: 110px !important; } - -.mb-11, -.my-11 { - margin-bottom: 110px !important; } - -.ml-11, -.mx-11 { - margin-left: 110px !important; } - -.m-12 { - margin: 120px !important; } - -.mt-12, -.my-12 { - margin-top: 120px !important; } - -.mr-12, -.mx-12 { - margin-right: 120px !important; } - -.mb-12, -.my-12 { - margin-bottom: 120px !important; } - -.ml-12, -.mx-12 { - margin-left: 120px !important; } - -.m-13 { - margin: 130px !important; } - -.mt-13, -.my-13 { - margin-top: 130px !important; } - -.mr-13, -.mx-13 { - margin-right: 130px !important; } - -.mb-13, -.my-13 { - margin-bottom: 130px !important; } - -.ml-13, -.mx-13 { - margin-left: 130px !important; } - -.m-14 { - margin: 140px !important; } - -.mt-14, -.my-14 { - margin-top: 140px !important; } - -.mr-14, -.mx-14 { - margin-right: 140px !important; } - -.mb-14, -.my-14 { - margin-bottom: 140px !important; } - -.ml-14, -.mx-14 { - margin-left: 140px !important; } - -.m-15 { - margin: 150px !important; } - -.mt-15, -.my-15 { - margin-top: 150px !important; } - -.mr-15, -.mx-15 { - margin-right: 150px !important; } - -.mb-15, -.my-15 { - margin-bottom: 150px !important; } - -.ml-15, -.mx-15 { - margin-left: 150px !important; } - -.m-16 { - margin: 160px !important; } - -.mt-16, -.my-16 { - margin-top: 160px !important; } - -.mr-16, -.mx-16 { - margin-right: 160px !important; } - -.mb-16, -.my-16 { - margin-bottom: 160px !important; } - -.ml-16, -.mx-16 { - margin-left: 160px !important; } - -.m-17 { - margin: 170px !important; } - -.mt-17, -.my-17 { - margin-top: 170px !important; } - -.mr-17, -.mx-17 { - margin-right: 170px !important; } - -.mb-17, -.my-17 { - margin-bottom: 170px !important; } - -.ml-17, -.mx-17 { - margin-left: 170px !important; } - -.m-18 { - margin: 180px !important; } - -.mt-18, -.my-18 { - margin-top: 180px !important; } - -.mr-18, -.mx-18 { - margin-right: 180px !important; } - -.mb-18, -.my-18 { - margin-bottom: 180px !important; } - -.ml-18, -.mx-18 { - margin-left: 180px !important; } - -.m-19 { - margin: 190px !important; } - -.mt-19, -.my-19 { - margin-top: 190px !important; } - -.mr-19, -.mx-19 { - margin-right: 190px !important; } - -.mb-19, -.my-19 { - margin-bottom: 190px !important; } - -.ml-19, -.mx-19 { - margin-left: 190px !important; } - -.m-20 { - margin: 200px !important; } - -.mt-20, -.my-20 { - margin-top: 200px !important; } - -.mr-20, -.mx-20 { - margin-right: 200px !important; } - -.mb-20, -.my-20 { - margin-bottom: 200px !important; } - -.ml-20, -.mx-20 { - margin-left: 200px !important; } - -.p-0 { - padding: 0 !important; } - -.pt-0, -.py-0 { - padding-top: 0 !important; } - -.pr-0, -.px-0 { - padding-right: 0 !important; } - -.pb-0, -.py-0 { - padding-bottom: 0 !important; } - -.pl-0, -.px-0 { - padding-left: 0 !important; } - -.p-1 { - padding: 10px !important; } - -.pt-1, -.py-1 { - padding-top: 10px !important; } - -.pr-1, -.px-1 { - padding-right: 10px !important; } - -.pb-1, -.py-1 { - padding-bottom: 10px !important; } - -.pl-1, -.px-1 { - padding-left: 10px !important; } - -.p-2 { - padding: 20px !important; } - -.pt-2, -.py-2 { - padding-top: 20px !important; } - -.pr-2, -.px-2 { - padding-right: 20px !important; } - -.pb-2, -.py-2 { - padding-bottom: 20px !important; } - -.pl-2, -.px-2 { - padding-left: 20px !important; } - -.p-3 { - padding: 30px !important; } - -.pt-3, -.py-3 { - padding-top: 30px !important; } - -.pr-3, -.px-3 { - padding-right: 30px !important; } - -.pb-3, -.py-3 { - padding-bottom: 30px !important; } - -.pl-3, -.px-3 { - padding-left: 30px !important; } - -.p-4 { - padding: 40px !important; } - -.pt-4, -.py-4 { - padding-top: 40px !important; } - -.pr-4, -.px-4 { - padding-right: 40px !important; } - -.pb-4, -.py-4 { - padding-bottom: 40px !important; } - -.pl-4, -.px-4 { - padding-left: 40px !important; } - -.p-5 { - padding: 50px !important; } - -.pt-5, -.py-5 { - padding-top: 50px !important; } - -.pr-5, -.px-5 { - padding-right: 50px !important; } - -.pb-5, -.py-5 { - padding-bottom: 50px !important; } - -.pl-5, -.px-5 { - padding-left: 50px !important; } - -.p-6 { - padding: 60px !important; } - -.pt-6, -.py-6 { - padding-top: 60px !important; } - -.pr-6, -.px-6 { - padding-right: 60px !important; } - -.pb-6, -.py-6 { - padding-bottom: 60px !important; } - -.pl-6, -.px-6 { - padding-left: 60px !important; } - -.p-7 { - padding: 70px !important; } - -.pt-7, -.py-7 { - padding-top: 70px !important; } - -.pr-7, -.px-7 { - padding-right: 70px !important; } - -.pb-7, -.py-7 { - padding-bottom: 70px !important; } - -.pl-7, -.px-7 { - padding-left: 70px !important; } - -.p-8 { - padding: 80px !important; } - -.pt-8, -.py-8 { - padding-top: 80px !important; } - -.pr-8, -.px-8 { - padding-right: 80px !important; } - -.pb-8, -.py-8 { - padding-bottom: 80px !important; } - -.pl-8, -.px-8 { - padding-left: 80px !important; } - -.p-9 { - padding: 90px !important; } - -.pt-9, -.py-9 { - padding-top: 90px !important; } - -.pr-9, -.px-9 { - padding-right: 90px !important; } - -.pb-9, -.py-9 { - padding-bottom: 90px !important; } - -.pl-9, -.px-9 { - padding-left: 90px !important; } - -.p-10 { - padding: 100px !important; } - -.pt-10, -.py-10 { - padding-top: 100px !important; } - -.pr-10, -.px-10 { - padding-right: 100px !important; } - -.pb-10, -.py-10 { - padding-bottom: 100px !important; } - -.pl-10, -.px-10 { - padding-left: 100px !important; } - -.p-11 { - padding: 110px !important; } - -.pt-11, -.py-11 { - padding-top: 110px !important; } - -.pr-11, -.px-11 { - padding-right: 110px !important; } - -.pb-11, -.py-11 { - padding-bottom: 110px !important; } - -.pl-11, -.px-11 { - padding-left: 110px !important; } - -.p-12 { - padding: 120px !important; } - -.pt-12, -.py-12 { - padding-top: 120px !important; } - -.pr-12, -.px-12 { - padding-right: 120px !important; } - -.pb-12, -.py-12 { - padding-bottom: 120px !important; } - -.pl-12, -.px-12 { - padding-left: 120px !important; } - -.p-13 { - padding: 130px !important; } - -.pt-13, -.py-13 { - padding-top: 130px !important; } - -.pr-13, -.px-13 { - padding-right: 130px !important; } - -.pb-13, -.py-13 { - padding-bottom: 130px !important; } - -.pl-13, -.px-13 { - padding-left: 130px !important; } - -.p-14 { - padding: 140px !important; } - -.pt-14, -.py-14 { - padding-top: 140px !important; } - -.pr-14, -.px-14 { - padding-right: 140px !important; } - -.pb-14, -.py-14 { - padding-bottom: 140px !important; } - -.pl-14, -.px-14 { - padding-left: 140px !important; } - -.p-15 { - padding: 150px !important; } - -.pt-15, -.py-15 { - padding-top: 150px !important; } - -.pr-15, -.px-15 { - padding-right: 150px !important; } - -.pb-15, -.py-15 { - padding-bottom: 150px !important; } - -.pl-15, -.px-15 { - padding-left: 150px !important; } - -.p-16 { - padding: 160px !important; } - -.pt-16, -.py-16 { - padding-top: 160px !important; } - -.pr-16, -.px-16 { - padding-right: 160px !important; } - -.pb-16, -.py-16 { - padding-bottom: 160px !important; } - -.pl-16, -.px-16 { - padding-left: 160px !important; } - -.p-17 { - padding: 170px !important; } - -.pt-17, -.py-17 { - padding-top: 170px !important; } - -.pr-17, -.px-17 { - padding-right: 170px !important; } - -.pb-17, -.py-17 { - padding-bottom: 170px !important; } - -.pl-17, -.px-17 { - padding-left: 170px !important; } - -.p-18 { - padding: 180px !important; } - -.pt-18, -.py-18 { - padding-top: 180px !important; } - -.pr-18, -.px-18 { - padding-right: 180px !important; } - -.pb-18, -.py-18 { - padding-bottom: 180px !important; } - -.pl-18, -.px-18 { - padding-left: 180px !important; } - -.p-19 { - padding: 190px !important; } - -.pt-19, -.py-19 { - padding-top: 190px !important; } - -.pr-19, -.px-19 { - padding-right: 190px !important; } - -.pb-19, -.py-19 { - padding-bottom: 190px !important; } - -.pl-19, -.px-19 { - padding-left: 190px !important; } - -.p-20 { - padding: 200px !important; } - -.pt-20, -.py-20 { - padding-top: 200px !important; } - -.pr-20, -.px-20 { - padding-right: 200px !important; } - -.pb-20, -.py-20 { - padding-bottom: 200px !important; } - -.pl-20, -.px-20 { - padding-left: 200px !important; } - -.m-auto { - margin: auto !important; } - -.mt-auto, -.my-auto { - margin-top: auto !important; } - -.mr-auto, -.mx-auto { - margin-right: auto !important; } - -.mb-auto, -.my-auto { - margin-bottom: auto !important; } - -.ml-auto, -.mx-auto { - margin-left: auto !important; } - -@media (min-width: 576px) { - .m-sm-0 { - margin: 0 !important; } - .mt-sm-0, - .my-sm-0 { - margin-top: 0 !important; } - .mr-sm-0, - .mx-sm-0 { - margin-right: 0 !important; } - .mb-sm-0, - .my-sm-0 { - margin-bottom: 0 !important; } - .ml-sm-0, - .mx-sm-0 { - margin-left: 0 !important; } - .m-sm-1 { - margin: 10px !important; } - .mt-sm-1, - .my-sm-1 { - margin-top: 10px !important; } - .mr-sm-1, - .mx-sm-1 { - margin-right: 10px !important; } - .mb-sm-1, - .my-sm-1 { - margin-bottom: 10px !important; } - .ml-sm-1, - .mx-sm-1 { - margin-left: 10px !important; } - .m-sm-2 { - margin: 20px !important; } - .mt-sm-2, - .my-sm-2 { - margin-top: 20px !important; } - .mr-sm-2, - .mx-sm-2 { - margin-right: 20px !important; } - .mb-sm-2, - .my-sm-2 { - margin-bottom: 20px !important; } - .ml-sm-2, - .mx-sm-2 { - margin-left: 20px !important; } - .m-sm-3 { - margin: 30px !important; } - .mt-sm-3, - .my-sm-3 { - margin-top: 30px !important; } - .mr-sm-3, - .mx-sm-3 { - margin-right: 30px !important; } - .mb-sm-3, - .my-sm-3 { - margin-bottom: 30px !important; } - .ml-sm-3, - .mx-sm-3 { - margin-left: 30px !important; } - .m-sm-4 { - margin: 40px !important; } - .mt-sm-4, - .my-sm-4 { - margin-top: 40px !important; } - .mr-sm-4, - .mx-sm-4 { - margin-right: 40px !important; } - .mb-sm-4, - .my-sm-4 { - margin-bottom: 40px !important; } - .ml-sm-4, - .mx-sm-4 { - margin-left: 40px !important; } - .m-sm-5 { - margin: 50px !important; } - .mt-sm-5, - .my-sm-5 { - margin-top: 50px !important; } - .mr-sm-5, - .mx-sm-5 { - margin-right: 50px !important; } - .mb-sm-5, - .my-sm-5 { - margin-bottom: 50px !important; } - .ml-sm-5, - .mx-sm-5 { - margin-left: 50px !important; } - .m-sm-6 { - margin: 60px !important; } - .mt-sm-6, - .my-sm-6 { - margin-top: 60px !important; } - .mr-sm-6, - .mx-sm-6 { - margin-right: 60px !important; } - .mb-sm-6, - .my-sm-6 { - margin-bottom: 60px !important; } - .ml-sm-6, - .mx-sm-6 { - margin-left: 60px !important; } - .m-sm-7 { - margin: 70px !important; } - .mt-sm-7, - .my-sm-7 { - margin-top: 70px !important; } - .mr-sm-7, - .mx-sm-7 { - margin-right: 70px !important; } - .mb-sm-7, - .my-sm-7 { - margin-bottom: 70px !important; } - .ml-sm-7, - .mx-sm-7 { - margin-left: 70px !important; } - .m-sm-8 { - margin: 80px !important; } - .mt-sm-8, - .my-sm-8 { - margin-top: 80px !important; } - .mr-sm-8, - .mx-sm-8 { - margin-right: 80px !important; } - .mb-sm-8, - .my-sm-8 { - margin-bottom: 80px !important; } - .ml-sm-8, - .mx-sm-8 { - margin-left: 80px !important; } - .m-sm-9 { - margin: 90px !important; } - .mt-sm-9, - .my-sm-9 { - margin-top: 90px !important; } - .mr-sm-9, - .mx-sm-9 { - margin-right: 90px !important; } - .mb-sm-9, - .my-sm-9 { - margin-bottom: 90px !important; } - .ml-sm-9, - .mx-sm-9 { - margin-left: 90px !important; } - .m-sm-10 { - margin: 100px !important; } - .mt-sm-10, - .my-sm-10 { - margin-top: 100px !important; } - .mr-sm-10, - .mx-sm-10 { - margin-right: 100px !important; } - .mb-sm-10, - .my-sm-10 { - margin-bottom: 100px !important; } - .ml-sm-10, - .mx-sm-10 { - margin-left: 100px !important; } - .m-sm-11 { - margin: 110px !important; } - .mt-sm-11, - .my-sm-11 { - margin-top: 110px !important; } - .mr-sm-11, - .mx-sm-11 { - margin-right: 110px !important; } - .mb-sm-11, - .my-sm-11 { - margin-bottom: 110px !important; } - .ml-sm-11, - .mx-sm-11 { - margin-left: 110px !important; } - .m-sm-12 { - margin: 120px !important; } - .mt-sm-12, - .my-sm-12 { - margin-top: 120px !important; } - .mr-sm-12, - .mx-sm-12 { - margin-right: 120px !important; } - .mb-sm-12, - .my-sm-12 { - margin-bottom: 120px !important; } - .ml-sm-12, - .mx-sm-12 { - margin-left: 120px !important; } - .m-sm-13 { - margin: 130px !important; } - .mt-sm-13, - .my-sm-13 { - margin-top: 130px !important; } - .mr-sm-13, - .mx-sm-13 { - margin-right: 130px !important; } - .mb-sm-13, - .my-sm-13 { - margin-bottom: 130px !important; } - .ml-sm-13, - .mx-sm-13 { - margin-left: 130px !important; } - .m-sm-14 { - margin: 140px !important; } - .mt-sm-14, - .my-sm-14 { - margin-top: 140px !important; } - .mr-sm-14, - .mx-sm-14 { - margin-right: 140px !important; } - .mb-sm-14, - .my-sm-14 { - margin-bottom: 140px !important; } - .ml-sm-14, - .mx-sm-14 { - margin-left: 140px !important; } - .m-sm-15 { - margin: 150px !important; } - .mt-sm-15, - .my-sm-15 { - margin-top: 150px !important; } - .mr-sm-15, - .mx-sm-15 { - margin-right: 150px !important; } - .mb-sm-15, - .my-sm-15 { - margin-bottom: 150px !important; } - .ml-sm-15, - .mx-sm-15 { - margin-left: 150px !important; } - .m-sm-16 { - margin: 160px !important; } - .mt-sm-16, - .my-sm-16 { - margin-top: 160px !important; } - .mr-sm-16, - .mx-sm-16 { - margin-right: 160px !important; } - .mb-sm-16, - .my-sm-16 { - margin-bottom: 160px !important; } - .ml-sm-16, - .mx-sm-16 { - margin-left: 160px !important; } - .m-sm-17 { - margin: 170px !important; } - .mt-sm-17, - .my-sm-17 { - margin-top: 170px !important; } - .mr-sm-17, - .mx-sm-17 { - margin-right: 170px !important; } - .mb-sm-17, - .my-sm-17 { - margin-bottom: 170px !important; } - .ml-sm-17, - .mx-sm-17 { - margin-left: 170px !important; } - .m-sm-18 { - margin: 180px !important; } - .mt-sm-18, - .my-sm-18 { - margin-top: 180px !important; } - .mr-sm-18, - .mx-sm-18 { - margin-right: 180px !important; } - .mb-sm-18, - .my-sm-18 { - margin-bottom: 180px !important; } - .ml-sm-18, - .mx-sm-18 { - margin-left: 180px !important; } - .m-sm-19 { - margin: 190px !important; } - .mt-sm-19, - .my-sm-19 { - margin-top: 190px !important; } - .mr-sm-19, - .mx-sm-19 { - margin-right: 190px !important; } - .mb-sm-19, - .my-sm-19 { - margin-bottom: 190px !important; } - .ml-sm-19, - .mx-sm-19 { - margin-left: 190px !important; } - .m-sm-20 { - margin: 200px !important; } - .mt-sm-20, - .my-sm-20 { - margin-top: 200px !important; } - .mr-sm-20, - .mx-sm-20 { - margin-right: 200px !important; } - .mb-sm-20, - .my-sm-20 { - margin-bottom: 200px !important; } - .ml-sm-20, - .mx-sm-20 { - margin-left: 200px !important; } - .p-sm-0 { - padding: 0 !important; } - .pt-sm-0, - .py-sm-0 { - padding-top: 0 !important; } - .pr-sm-0, - .px-sm-0 { - padding-right: 0 !important; } - .pb-sm-0, - .py-sm-0 { - padding-bottom: 0 !important; } - .pl-sm-0, - .px-sm-0 { - padding-left: 0 !important; } - .p-sm-1 { - padding: 10px !important; } - .pt-sm-1, - .py-sm-1 { - padding-top: 10px !important; } - .pr-sm-1, - .px-sm-1 { - padding-right: 10px !important; } - .pb-sm-1, - .py-sm-1 { - padding-bottom: 10px !important; } - .pl-sm-1, - .px-sm-1 { - padding-left: 10px !important; } - .p-sm-2 { - padding: 20px !important; } - .pt-sm-2, - .py-sm-2 { - padding-top: 20px !important; } - .pr-sm-2, - .px-sm-2 { - padding-right: 20px !important; } - .pb-sm-2, - .py-sm-2 { - padding-bottom: 20px !important; } - .pl-sm-2, - .px-sm-2 { - padding-left: 20px !important; } - .p-sm-3 { - padding: 30px !important; } - .pt-sm-3, - .py-sm-3 { - padding-top: 30px !important; } - .pr-sm-3, - .px-sm-3 { - padding-right: 30px !important; } - .pb-sm-3, - .py-sm-3 { - padding-bottom: 30px !important; } - .pl-sm-3, - .px-sm-3 { - padding-left: 30px !important; } - .p-sm-4 { - padding: 40px !important; } - .pt-sm-4, - .py-sm-4 { - padding-top: 40px !important; } - .pr-sm-4, - .px-sm-4 { - padding-right: 40px !important; } - .pb-sm-4, - .py-sm-4 { - padding-bottom: 40px !important; } - .pl-sm-4, - .px-sm-4 { - padding-left: 40px !important; } - .p-sm-5 { - padding: 50px !important; } - .pt-sm-5, - .py-sm-5 { - padding-top: 50px !important; } - .pr-sm-5, - .px-sm-5 { - padding-right: 50px !important; } - .pb-sm-5, - .py-sm-5 { - padding-bottom: 50px !important; } - .pl-sm-5, - .px-sm-5 { - padding-left: 50px !important; } - .p-sm-6 { - padding: 60px !important; } - .pt-sm-6, - .py-sm-6 { - padding-top: 60px !important; } - .pr-sm-6, - .px-sm-6 { - padding-right: 60px !important; } - .pb-sm-6, - .py-sm-6 { - padding-bottom: 60px !important; } - .pl-sm-6, - .px-sm-6 { - padding-left: 60px !important; } - .p-sm-7 { - padding: 70px !important; } - .pt-sm-7, - .py-sm-7 { - padding-top: 70px !important; } - .pr-sm-7, - .px-sm-7 { - padding-right: 70px !important; } - .pb-sm-7, - .py-sm-7 { - padding-bottom: 70px !important; } - .pl-sm-7, - .px-sm-7 { - padding-left: 70px !important; } - .p-sm-8 { - padding: 80px !important; } - .pt-sm-8, - .py-sm-8 { - padding-top: 80px !important; } - .pr-sm-8, - .px-sm-8 { - padding-right: 80px !important; } - .pb-sm-8, - .py-sm-8 { - padding-bottom: 80px !important; } - .pl-sm-8, - .px-sm-8 { - padding-left: 80px !important; } - .p-sm-9 { - padding: 90px !important; } - .pt-sm-9, - .py-sm-9 { - padding-top: 90px !important; } - .pr-sm-9, - .px-sm-9 { - padding-right: 90px !important; } - .pb-sm-9, - .py-sm-9 { - padding-bottom: 90px !important; } - .pl-sm-9, - .px-sm-9 { - padding-left: 90px !important; } - .p-sm-10 { - padding: 100px !important; } - .pt-sm-10, - .py-sm-10 { - padding-top: 100px !important; } - .pr-sm-10, - .px-sm-10 { - padding-right: 100px !important; } - .pb-sm-10, - .py-sm-10 { - padding-bottom: 100px !important; } - .pl-sm-10, - .px-sm-10 { - padding-left: 100px !important; } - .p-sm-11 { - padding: 110px !important; } - .pt-sm-11, - .py-sm-11 { - padding-top: 110px !important; } - .pr-sm-11, - .px-sm-11 { - padding-right: 110px !important; } - .pb-sm-11, - .py-sm-11 { - padding-bottom: 110px !important; } - .pl-sm-11, - .px-sm-11 { - padding-left: 110px !important; } - .p-sm-12 { - padding: 120px !important; } - .pt-sm-12, - .py-sm-12 { - padding-top: 120px !important; } - .pr-sm-12, - .px-sm-12 { - padding-right: 120px !important; } - .pb-sm-12, - .py-sm-12 { - padding-bottom: 120px !important; } - .pl-sm-12, - .px-sm-12 { - padding-left: 120px !important; } - .p-sm-13 { - padding: 130px !important; } - .pt-sm-13, - .py-sm-13 { - padding-top: 130px !important; } - .pr-sm-13, - .px-sm-13 { - padding-right: 130px !important; } - .pb-sm-13, - .py-sm-13 { - padding-bottom: 130px !important; } - .pl-sm-13, - .px-sm-13 { - padding-left: 130px !important; } - .p-sm-14 { - padding: 140px !important; } - .pt-sm-14, - .py-sm-14 { - padding-top: 140px !important; } - .pr-sm-14, - .px-sm-14 { - padding-right: 140px !important; } - .pb-sm-14, - .py-sm-14 { - padding-bottom: 140px !important; } - .pl-sm-14, - .px-sm-14 { - padding-left: 140px !important; } - .p-sm-15 { - padding: 150px !important; } - .pt-sm-15, - .py-sm-15 { - padding-top: 150px !important; } - .pr-sm-15, - .px-sm-15 { - padding-right: 150px !important; } - .pb-sm-15, - .py-sm-15 { - padding-bottom: 150px !important; } - .pl-sm-15, - .px-sm-15 { - padding-left: 150px !important; } - .p-sm-16 { - padding: 160px !important; } - .pt-sm-16, - .py-sm-16 { - padding-top: 160px !important; } - .pr-sm-16, - .px-sm-16 { - padding-right: 160px !important; } - .pb-sm-16, - .py-sm-16 { - padding-bottom: 160px !important; } - .pl-sm-16, - .px-sm-16 { - padding-left: 160px !important; } - .p-sm-17 { - padding: 170px !important; } - .pt-sm-17, - .py-sm-17 { - padding-top: 170px !important; } - .pr-sm-17, - .px-sm-17 { - padding-right: 170px !important; } - .pb-sm-17, - .py-sm-17 { - padding-bottom: 170px !important; } - .pl-sm-17, - .px-sm-17 { - padding-left: 170px !important; } - .p-sm-18 { - padding: 180px !important; } - .pt-sm-18, - .py-sm-18 { - padding-top: 180px !important; } - .pr-sm-18, - .px-sm-18 { - padding-right: 180px !important; } - .pb-sm-18, - .py-sm-18 { - padding-bottom: 180px !important; } - .pl-sm-18, - .px-sm-18 { - padding-left: 180px !important; } - .p-sm-19 { - padding: 190px !important; } - .pt-sm-19, - .py-sm-19 { - padding-top: 190px !important; } - .pr-sm-19, - .px-sm-19 { - padding-right: 190px !important; } - .pb-sm-19, - .py-sm-19 { - padding-bottom: 190px !important; } - .pl-sm-19, - .px-sm-19 { - padding-left: 190px !important; } - .p-sm-20 { - padding: 200px !important; } - .pt-sm-20, - .py-sm-20 { - padding-top: 200px !important; } - .pr-sm-20, - .px-sm-20 { - padding-right: 200px !important; } - .pb-sm-20, - .py-sm-20 { - padding-bottom: 200px !important; } - .pl-sm-20, - .px-sm-20 { - padding-left: 200px !important; } - .m-sm-auto { - margin: auto !important; } - .mt-sm-auto, - .my-sm-auto { - margin-top: auto !important; } - .mr-sm-auto, - .mx-sm-auto { - margin-right: auto !important; } - .mb-sm-auto, - .my-sm-auto { - margin-bottom: auto !important; } - .ml-sm-auto, - .mx-sm-auto { - margin-left: auto !important; } } - -@media (min-width: 768px) { - .m-md-0 { - margin: 0 !important; } - .mt-md-0, - .my-md-0 { - margin-top: 0 !important; } - .mr-md-0, - .mx-md-0 { - margin-right: 0 !important; } - .mb-md-0, - .my-md-0 { - margin-bottom: 0 !important; } - .ml-md-0, - .mx-md-0 { - margin-left: 0 !important; } - .m-md-1 { - margin: 10px !important; } - .mt-md-1, - .my-md-1 { - margin-top: 10px !important; } - .mr-md-1, - .mx-md-1 { - margin-right: 10px !important; } - .mb-md-1, - .my-md-1 { - margin-bottom: 10px !important; } - .ml-md-1, - .mx-md-1 { - margin-left: 10px !important; } - .m-md-2 { - margin: 20px !important; } - .mt-md-2, - .my-md-2 { - margin-top: 20px !important; } - .mr-md-2, - .mx-md-2 { - margin-right: 20px !important; } - .mb-md-2, - .my-md-2 { - margin-bottom: 20px !important; } - .ml-md-2, - .mx-md-2 { - margin-left: 20px !important; } - .m-md-3 { - margin: 30px !important; } - .mt-md-3, - .my-md-3 { - margin-top: 30px !important; } - .mr-md-3, - .mx-md-3 { - margin-right: 30px !important; } - .mb-md-3, - .my-md-3 { - margin-bottom: 30px !important; } - .ml-md-3, - .mx-md-3 { - margin-left: 30px !important; } - .m-md-4 { - margin: 40px !important; } - .mt-md-4, - .my-md-4 { - margin-top: 40px !important; } - .mr-md-4, - .mx-md-4 { - margin-right: 40px !important; } - .mb-md-4, - .my-md-4 { - margin-bottom: 40px !important; } - .ml-md-4, - .mx-md-4 { - margin-left: 40px !important; } - .m-md-5 { - margin: 50px !important; } - .mt-md-5, - .my-md-5 { - margin-top: 50px !important; } - .mr-md-5, - .mx-md-5 { - margin-right: 50px !important; } - .mb-md-5, - .my-md-5 { - margin-bottom: 50px !important; } - .ml-md-5, - .mx-md-5 { - margin-left: 50px !important; } - .m-md-6 { - margin: 60px !important; } - .mt-md-6, - .my-md-6 { - margin-top: 60px !important; } - .mr-md-6, - .mx-md-6 { - margin-right: 60px !important; } - .mb-md-6, - .my-md-6 { - margin-bottom: 60px !important; } - .ml-md-6, - .mx-md-6 { - margin-left: 60px !important; } - .m-md-7 { - margin: 70px !important; } - .mt-md-7, - .my-md-7 { - margin-top: 70px !important; } - .mr-md-7, - .mx-md-7 { - margin-right: 70px !important; } - .mb-md-7, - .my-md-7 { - margin-bottom: 70px !important; } - .ml-md-7, - .mx-md-7 { - margin-left: 70px !important; } - .m-md-8 { - margin: 80px !important; } - .mt-md-8, - .my-md-8 { - margin-top: 80px !important; } - .mr-md-8, - .mx-md-8 { - margin-right: 80px !important; } - .mb-md-8, - .my-md-8 { - margin-bottom: 80px !important; } - .ml-md-8, - .mx-md-8 { - margin-left: 80px !important; } - .m-md-9 { - margin: 90px !important; } - .mt-md-9, - .my-md-9 { - margin-top: 90px !important; } - .mr-md-9, - .mx-md-9 { - margin-right: 90px !important; } - .mb-md-9, - .my-md-9 { - margin-bottom: 90px !important; } - .ml-md-9, - .mx-md-9 { - margin-left: 90px !important; } - .m-md-10 { - margin: 100px !important; } - .mt-md-10, - .my-md-10 { - margin-top: 100px !important; } - .mr-md-10, - .mx-md-10 { - margin-right: 100px !important; } - .mb-md-10, - .my-md-10 { - margin-bottom: 100px !important; } - .ml-md-10, - .mx-md-10 { - margin-left: 100px !important; } - .m-md-11 { - margin: 110px !important; } - .mt-md-11, - .my-md-11 { - margin-top: 110px !important; } - .mr-md-11, - .mx-md-11 { - margin-right: 110px !important; } - .mb-md-11, - .my-md-11 { - margin-bottom: 110px !important; } - .ml-md-11, - .mx-md-11 { - margin-left: 110px !important; } - .m-md-12 { - margin: 120px !important; } - .mt-md-12, - .my-md-12 { - margin-top: 120px !important; } - .mr-md-12, - .mx-md-12 { - margin-right: 120px !important; } - .mb-md-12, - .my-md-12 { - margin-bottom: 120px !important; } - .ml-md-12, - .mx-md-12 { - margin-left: 120px !important; } - .m-md-13 { - margin: 130px !important; } - .mt-md-13, - .my-md-13 { - margin-top: 130px !important; } - .mr-md-13, - .mx-md-13 { - margin-right: 130px !important; } - .mb-md-13, - .my-md-13 { - margin-bottom: 130px !important; } - .ml-md-13, - .mx-md-13 { - margin-left: 130px !important; } - .m-md-14 { - margin: 140px !important; } - .mt-md-14, - .my-md-14 { - margin-top: 140px !important; } - .mr-md-14, - .mx-md-14 { - margin-right: 140px !important; } - .mb-md-14, - .my-md-14 { - margin-bottom: 140px !important; } - .ml-md-14, - .mx-md-14 { - margin-left: 140px !important; } - .m-md-15 { - margin: 150px !important; } - .mt-md-15, - .my-md-15 { - margin-top: 150px !important; } - .mr-md-15, - .mx-md-15 { - margin-right: 150px !important; } - .mb-md-15, - .my-md-15 { - margin-bottom: 150px !important; } - .ml-md-15, - .mx-md-15 { - margin-left: 150px !important; } - .m-md-16 { - margin: 160px !important; } - .mt-md-16, - .my-md-16 { - margin-top: 160px !important; } - .mr-md-16, - .mx-md-16 { - margin-right: 160px !important; } - .mb-md-16, - .my-md-16 { - margin-bottom: 160px !important; } - .ml-md-16, - .mx-md-16 { - margin-left: 160px !important; } - .m-md-17 { - margin: 170px !important; } - .mt-md-17, - .my-md-17 { - margin-top: 170px !important; } - .mr-md-17, - .mx-md-17 { - margin-right: 170px !important; } - .mb-md-17, - .my-md-17 { - margin-bottom: 170px !important; } - .ml-md-17, - .mx-md-17 { - margin-left: 170px !important; } - .m-md-18 { - margin: 180px !important; } - .mt-md-18, - .my-md-18 { - margin-top: 180px !important; } - .mr-md-18, - .mx-md-18 { - margin-right: 180px !important; } - .mb-md-18, - .my-md-18 { - margin-bottom: 180px !important; } - .ml-md-18, - .mx-md-18 { - margin-left: 180px !important; } - .m-md-19 { - margin: 190px !important; } - .mt-md-19, - .my-md-19 { - margin-top: 190px !important; } - .mr-md-19, - .mx-md-19 { - margin-right: 190px !important; } - .mb-md-19, - .my-md-19 { - margin-bottom: 190px !important; } - .ml-md-19, - .mx-md-19 { - margin-left: 190px !important; } - .m-md-20 { - margin: 200px !important; } - .mt-md-20, - .my-md-20 { - margin-top: 200px !important; } - .mr-md-20, - .mx-md-20 { - margin-right: 200px !important; } - .mb-md-20, - .my-md-20 { - margin-bottom: 200px !important; } - .ml-md-20, - .mx-md-20 { - margin-left: 200px !important; } - .p-md-0 { - padding: 0 !important; } - .pt-md-0, - .py-md-0 { - padding-top: 0 !important; } - .pr-md-0, - .px-md-0 { - padding-right: 0 !important; } - .pb-md-0, - .py-md-0 { - padding-bottom: 0 !important; } - .pl-md-0, - .px-md-0 { - padding-left: 0 !important; } - .p-md-1 { - padding: 10px !important; } - .pt-md-1, - .py-md-1 { - padding-top: 10px !important; } - .pr-md-1, - .px-md-1 { - padding-right: 10px !important; } - .pb-md-1, - .py-md-1 { - padding-bottom: 10px !important; } - .pl-md-1, - .px-md-1 { - padding-left: 10px !important; } - .p-md-2 { - padding: 20px !important; } - .pt-md-2, - .py-md-2 { - padding-top: 20px !important; } - .pr-md-2, - .px-md-2 { - padding-right: 20px !important; } - .pb-md-2, - .py-md-2 { - padding-bottom: 20px !important; } - .pl-md-2, - .px-md-2 { - padding-left: 20px !important; } - .p-md-3 { - padding: 30px !important; } - .pt-md-3, - .py-md-3 { - padding-top: 30px !important; } - .pr-md-3, - .px-md-3 { - padding-right: 30px !important; } - .pb-md-3, - .py-md-3 { - padding-bottom: 30px !important; } - .pl-md-3, - .px-md-3 { - padding-left: 30px !important; } - .p-md-4 { - padding: 40px !important; } - .pt-md-4, - .py-md-4 { - padding-top: 40px !important; } - .pr-md-4, - .px-md-4 { - padding-right: 40px !important; } - .pb-md-4, - .py-md-4 { - padding-bottom: 40px !important; } - .pl-md-4, - .px-md-4 { - padding-left: 40px !important; } - .p-md-5 { - padding: 50px !important; } - .pt-md-5, - .py-md-5 { - padding-top: 50px !important; } - .pr-md-5, - .px-md-5 { - padding-right: 50px !important; } - .pb-md-5, - .py-md-5 { - padding-bottom: 50px !important; } - .pl-md-5, - .px-md-5 { - padding-left: 50px !important; } - .p-md-6 { - padding: 60px !important; } - .pt-md-6, - .py-md-6 { - padding-top: 60px !important; } - .pr-md-6, - .px-md-6 { - padding-right: 60px !important; } - .pb-md-6, - .py-md-6 { - padding-bottom: 60px !important; } - .pl-md-6, - .px-md-6 { - padding-left: 60px !important; } - .p-md-7 { - padding: 70px !important; } - .pt-md-7, - .py-md-7 { - padding-top: 70px !important; } - .pr-md-7, - .px-md-7 { - padding-right: 70px !important; } - .pb-md-7, - .py-md-7 { - padding-bottom: 70px !important; } - .pl-md-7, - .px-md-7 { - padding-left: 70px !important; } - .p-md-8 { - padding: 80px !important; } - .pt-md-8, - .py-md-8 { - padding-top: 80px !important; } - .pr-md-8, - .px-md-8 { - padding-right: 80px !important; } - .pb-md-8, - .py-md-8 { - padding-bottom: 80px !important; } - .pl-md-8, - .px-md-8 { - padding-left: 80px !important; } - .p-md-9 { - padding: 90px !important; } - .pt-md-9, - .py-md-9 { - padding-top: 90px !important; } - .pr-md-9, - .px-md-9 { - padding-right: 90px !important; } - .pb-md-9, - .py-md-9 { - padding-bottom: 90px !important; } - .pl-md-9, - .px-md-9 { - padding-left: 90px !important; } - .p-md-10 { - padding: 100px !important; } - .pt-md-10, - .py-md-10 { - padding-top: 100px !important; } - .pr-md-10, - .px-md-10 { - padding-right: 100px !important; } - .pb-md-10, - .py-md-10 { - padding-bottom: 100px !important; } - .pl-md-10, - .px-md-10 { - padding-left: 100px !important; } - .p-md-11 { - padding: 110px !important; } - .pt-md-11, - .py-md-11 { - padding-top: 110px !important; } - .pr-md-11, - .px-md-11 { - padding-right: 110px !important; } - .pb-md-11, - .py-md-11 { - padding-bottom: 110px !important; } - .pl-md-11, - .px-md-11 { - padding-left: 110px !important; } - .p-md-12 { - padding: 120px !important; } - .pt-md-12, - .py-md-12 { - padding-top: 120px !important; } - .pr-md-12, - .px-md-12 { - padding-right: 120px !important; } - .pb-md-12, - .py-md-12 { - padding-bottom: 120px !important; } - .pl-md-12, - .px-md-12 { - padding-left: 120px !important; } - .p-md-13 { - padding: 130px !important; } - .pt-md-13, - .py-md-13 { - padding-top: 130px !important; } - .pr-md-13, - .px-md-13 { - padding-right: 130px !important; } - .pb-md-13, - .py-md-13 { - padding-bottom: 130px !important; } - .pl-md-13, - .px-md-13 { - padding-left: 130px !important; } - .p-md-14 { - padding: 140px !important; } - .pt-md-14, - .py-md-14 { - padding-top: 140px !important; } - .pr-md-14, - .px-md-14 { - padding-right: 140px !important; } - .pb-md-14, - .py-md-14 { - padding-bottom: 140px !important; } - .pl-md-14, - .px-md-14 { - padding-left: 140px !important; } - .p-md-15 { - padding: 150px !important; } - .pt-md-15, - .py-md-15 { - padding-top: 150px !important; } - .pr-md-15, - .px-md-15 { - padding-right: 150px !important; } - .pb-md-15, - .py-md-15 { - padding-bottom: 150px !important; } - .pl-md-15, - .px-md-15 { - padding-left: 150px !important; } - .p-md-16 { - padding: 160px !important; } - .pt-md-16, - .py-md-16 { - padding-top: 160px !important; } - .pr-md-16, - .px-md-16 { - padding-right: 160px !important; } - .pb-md-16, - .py-md-16 { - padding-bottom: 160px !important; } - .pl-md-16, - .px-md-16 { - padding-left: 160px !important; } - .p-md-17 { - padding: 170px !important; } - .pt-md-17, - .py-md-17 { - padding-top: 170px !important; } - .pr-md-17, - .px-md-17 { - padding-right: 170px !important; } - .pb-md-17, - .py-md-17 { - padding-bottom: 170px !important; } - .pl-md-17, - .px-md-17 { - padding-left: 170px !important; } - .p-md-18 { - padding: 180px !important; } - .pt-md-18, - .py-md-18 { - padding-top: 180px !important; } - .pr-md-18, - .px-md-18 { - padding-right: 180px !important; } - .pb-md-18, - .py-md-18 { - padding-bottom: 180px !important; } - .pl-md-18, - .px-md-18 { - padding-left: 180px !important; } - .p-md-19 { - padding: 190px !important; } - .pt-md-19, - .py-md-19 { - padding-top: 190px !important; } - .pr-md-19, - .px-md-19 { - padding-right: 190px !important; } - .pb-md-19, - .py-md-19 { - padding-bottom: 190px !important; } - .pl-md-19, - .px-md-19 { - padding-left: 190px !important; } - .p-md-20 { - padding: 200px !important; } - .pt-md-20, - .py-md-20 { - padding-top: 200px !important; } - .pr-md-20, - .px-md-20 { - padding-right: 200px !important; } - .pb-md-20, - .py-md-20 { - padding-bottom: 200px !important; } - .pl-md-20, - .px-md-20 { - padding-left: 200px !important; } - .m-md-auto { - margin: auto !important; } - .mt-md-auto, - .my-md-auto { - margin-top: auto !important; } - .mr-md-auto, - .mx-md-auto { - margin-right: auto !important; } - .mb-md-auto, - .my-md-auto { - margin-bottom: auto !important; } - .ml-md-auto, - .mx-md-auto { - margin-left: auto !important; } } - -@media (min-width: 992px) { - .m-lg-0 { - margin: 0 !important; } - .mt-lg-0, - .my-lg-0 { - margin-top: 0 !important; } - .mr-lg-0, - .mx-lg-0 { - margin-right: 0 !important; } - .mb-lg-0, - .my-lg-0 { - margin-bottom: 0 !important; } - .ml-lg-0, - .mx-lg-0 { - margin-left: 0 !important; } - .m-lg-1 { - margin: 10px !important; } - .mt-lg-1, - .my-lg-1 { - margin-top: 10px !important; } - .mr-lg-1, - .mx-lg-1 { - margin-right: 10px !important; } - .mb-lg-1, - .my-lg-1 { - margin-bottom: 10px !important; } - .ml-lg-1, - .mx-lg-1 { - margin-left: 10px !important; } - .m-lg-2 { - margin: 20px !important; } - .mt-lg-2, - .my-lg-2 { - margin-top: 20px !important; } - .mr-lg-2, - .mx-lg-2 { - margin-right: 20px !important; } - .mb-lg-2, - .my-lg-2 { - margin-bottom: 20px !important; } - .ml-lg-2, - .mx-lg-2 { - margin-left: 20px !important; } - .m-lg-3 { - margin: 30px !important; } - .mt-lg-3, - .my-lg-3 { - margin-top: 30px !important; } - .mr-lg-3, - .mx-lg-3 { - margin-right: 30px !important; } - .mb-lg-3, - .my-lg-3 { - margin-bottom: 30px !important; } - .ml-lg-3, - .mx-lg-3 { - margin-left: 30px !important; } - .m-lg-4 { - margin: 40px !important; } - .mt-lg-4, - .my-lg-4 { - margin-top: 40px !important; } - .mr-lg-4, - .mx-lg-4 { - margin-right: 40px !important; } - .mb-lg-4, - .my-lg-4 { - margin-bottom: 40px !important; } - .ml-lg-4, - .mx-lg-4 { - margin-left: 40px !important; } - .m-lg-5 { - margin: 50px !important; } - .mt-lg-5, - .my-lg-5 { - margin-top: 50px !important; } - .mr-lg-5, - .mx-lg-5 { - margin-right: 50px !important; } - .mb-lg-5, - .my-lg-5 { - margin-bottom: 50px !important; } - .ml-lg-5, - .mx-lg-5 { - margin-left: 50px !important; } - .m-lg-6 { - margin: 60px !important; } - .mt-lg-6, - .my-lg-6 { - margin-top: 60px !important; } - .mr-lg-6, - .mx-lg-6 { - margin-right: 60px !important; } - .mb-lg-6, - .my-lg-6 { - margin-bottom: 60px !important; } - .ml-lg-6, - .mx-lg-6 { - margin-left: 60px !important; } - .m-lg-7 { - margin: 70px !important; } - .mt-lg-7, - .my-lg-7 { - margin-top: 70px !important; } - .mr-lg-7, - .mx-lg-7 { - margin-right: 70px !important; } - .mb-lg-7, - .my-lg-7 { - margin-bottom: 70px !important; } - .ml-lg-7, - .mx-lg-7 { - margin-left: 70px !important; } - .m-lg-8 { - margin: 80px !important; } - .mt-lg-8, - .my-lg-8 { - margin-top: 80px !important; } - .mr-lg-8, - .mx-lg-8 { - margin-right: 80px !important; } - .mb-lg-8, - .my-lg-8 { - margin-bottom: 80px !important; } - .ml-lg-8, - .mx-lg-8 { - margin-left: 80px !important; } - .m-lg-9 { - margin: 90px !important; } - .mt-lg-9, - .my-lg-9 { - margin-top: 90px !important; } - .mr-lg-9, - .mx-lg-9 { - margin-right: 90px !important; } - .mb-lg-9, - .my-lg-9 { - margin-bottom: 90px !important; } - .ml-lg-9, - .mx-lg-9 { - margin-left: 90px !important; } - .m-lg-10 { - margin: 100px !important; } - .mt-lg-10, - .my-lg-10 { - margin-top: 100px !important; } - .mr-lg-10, - .mx-lg-10 { - margin-right: 100px !important; } - .mb-lg-10, - .my-lg-10 { - margin-bottom: 100px !important; } - .ml-lg-10, - .mx-lg-10 { - margin-left: 100px !important; } - .m-lg-11 { - margin: 110px !important; } - .mt-lg-11, - .my-lg-11 { - margin-top: 110px !important; } - .mr-lg-11, - .mx-lg-11 { - margin-right: 110px !important; } - .mb-lg-11, - .my-lg-11 { - margin-bottom: 110px !important; } - .ml-lg-11, - .mx-lg-11 { - margin-left: 110px !important; } - .m-lg-12 { - margin: 120px !important; } - .mt-lg-12, - .my-lg-12 { - margin-top: 120px !important; } - .mr-lg-12, - .mx-lg-12 { - margin-right: 120px !important; } - .mb-lg-12, - .my-lg-12 { - margin-bottom: 120px !important; } - .ml-lg-12, - .mx-lg-12 { - margin-left: 120px !important; } - .m-lg-13 { - margin: 130px !important; } - .mt-lg-13, - .my-lg-13 { - margin-top: 130px !important; } - .mr-lg-13, - .mx-lg-13 { - margin-right: 130px !important; } - .mb-lg-13, - .my-lg-13 { - margin-bottom: 130px !important; } - .ml-lg-13, - .mx-lg-13 { - margin-left: 130px !important; } - .m-lg-14 { - margin: 140px !important; } - .mt-lg-14, - .my-lg-14 { - margin-top: 140px !important; } - .mr-lg-14, - .mx-lg-14 { - margin-right: 140px !important; } - .mb-lg-14, - .my-lg-14 { - margin-bottom: 140px !important; } - .ml-lg-14, - .mx-lg-14 { - margin-left: 140px !important; } - .m-lg-15 { - margin: 150px !important; } - .mt-lg-15, - .my-lg-15 { - margin-top: 150px !important; } - .mr-lg-15, - .mx-lg-15 { - margin-right: 150px !important; } - .mb-lg-15, - .my-lg-15 { - margin-bottom: 150px !important; } - .ml-lg-15, - .mx-lg-15 { - margin-left: 150px !important; } - .m-lg-16 { - margin: 160px !important; } - .mt-lg-16, - .my-lg-16 { - margin-top: 160px !important; } - .mr-lg-16, - .mx-lg-16 { - margin-right: 160px !important; } - .mb-lg-16, - .my-lg-16 { - margin-bottom: 160px !important; } - .ml-lg-16, - .mx-lg-16 { - margin-left: 160px !important; } - .m-lg-17 { - margin: 170px !important; } - .mt-lg-17, - .my-lg-17 { - margin-top: 170px !important; } - .mr-lg-17, - .mx-lg-17 { - margin-right: 170px !important; } - .mb-lg-17, - .my-lg-17 { - margin-bottom: 170px !important; } - .ml-lg-17, - .mx-lg-17 { - margin-left: 170px !important; } - .m-lg-18 { - margin: 180px !important; } - .mt-lg-18, - .my-lg-18 { - margin-top: 180px !important; } - .mr-lg-18, - .mx-lg-18 { - margin-right: 180px !important; } - .mb-lg-18, - .my-lg-18 { - margin-bottom: 180px !important; } - .ml-lg-18, - .mx-lg-18 { - margin-left: 180px !important; } - .m-lg-19 { - margin: 190px !important; } - .mt-lg-19, - .my-lg-19 { - margin-top: 190px !important; } - .mr-lg-19, - .mx-lg-19 { - margin-right: 190px !important; } - .mb-lg-19, - .my-lg-19 { - margin-bottom: 190px !important; } - .ml-lg-19, - .mx-lg-19 { - margin-left: 190px !important; } - .m-lg-20 { - margin: 200px !important; } - .mt-lg-20, - .my-lg-20 { - margin-top: 200px !important; } - .mr-lg-20, - .mx-lg-20 { - margin-right: 200px !important; } - .mb-lg-20, - .my-lg-20 { - margin-bottom: 200px !important; } - .ml-lg-20, - .mx-lg-20 { - margin-left: 200px !important; } - .p-lg-0 { - padding: 0 !important; } - .pt-lg-0, - .py-lg-0 { - padding-top: 0 !important; } - .pr-lg-0, - .px-lg-0 { - padding-right: 0 !important; } - .pb-lg-0, - .py-lg-0 { - padding-bottom: 0 !important; } - .pl-lg-0, - .px-lg-0 { - padding-left: 0 !important; } - .p-lg-1 { - padding: 10px !important; } - .pt-lg-1, - .py-lg-1 { - padding-top: 10px !important; } - .pr-lg-1, - .px-lg-1 { - padding-right: 10px !important; } - .pb-lg-1, - .py-lg-1 { - padding-bottom: 10px !important; } - .pl-lg-1, - .px-lg-1 { - padding-left: 10px !important; } - .p-lg-2 { - padding: 20px !important; } - .pt-lg-2, - .py-lg-2 { - padding-top: 20px !important; } - .pr-lg-2, - .px-lg-2 { - padding-right: 20px !important; } - .pb-lg-2, - .py-lg-2 { - padding-bottom: 20px !important; } - .pl-lg-2, - .px-lg-2 { - padding-left: 20px !important; } - .p-lg-3 { - padding: 30px !important; } - .pt-lg-3, - .py-lg-3 { - padding-top: 30px !important; } - .pr-lg-3, - .px-lg-3 { - padding-right: 30px !important; } - .pb-lg-3, - .py-lg-3 { - padding-bottom: 30px !important; } - .pl-lg-3, - .px-lg-3 { - padding-left: 30px !important; } - .p-lg-4 { - padding: 40px !important; } - .pt-lg-4, - .py-lg-4 { - padding-top: 40px !important; } - .pr-lg-4, - .px-lg-4 { - padding-right: 40px !important; } - .pb-lg-4, - .py-lg-4 { - padding-bottom: 40px !important; } - .pl-lg-4, - .px-lg-4 { - padding-left: 40px !important; } - .p-lg-5 { - padding: 50px !important; } - .pt-lg-5, - .py-lg-5 { - padding-top: 50px !important; } - .pr-lg-5, - .px-lg-5 { - padding-right: 50px !important; } - .pb-lg-5, - .py-lg-5 { - padding-bottom: 50px !important; } - .pl-lg-5, - .px-lg-5 { - padding-left: 50px !important; } - .p-lg-6 { - padding: 60px !important; } - .pt-lg-6, - .py-lg-6 { - padding-top: 60px !important; } - .pr-lg-6, - .px-lg-6 { - padding-right: 60px !important; } - .pb-lg-6, - .py-lg-6 { - padding-bottom: 60px !important; } - .pl-lg-6, - .px-lg-6 { - padding-left: 60px !important; } - .p-lg-7 { - padding: 70px !important; } - .pt-lg-7, - .py-lg-7 { - padding-top: 70px !important; } - .pr-lg-7, - .px-lg-7 { - padding-right: 70px !important; } - .pb-lg-7, - .py-lg-7 { - padding-bottom: 70px !important; } - .pl-lg-7, - .px-lg-7 { - padding-left: 70px !important; } - .p-lg-8 { - padding: 80px !important; } - .pt-lg-8, - .py-lg-8 { - padding-top: 80px !important; } - .pr-lg-8, - .px-lg-8 { - padding-right: 80px !important; } - .pb-lg-8, - .py-lg-8 { - padding-bottom: 80px !important; } - .pl-lg-8, - .px-lg-8 { - padding-left: 80px !important; } - .p-lg-9 { - padding: 90px !important; } - .pt-lg-9, - .py-lg-9 { - padding-top: 90px !important; } - .pr-lg-9, - .px-lg-9 { - padding-right: 90px !important; } - .pb-lg-9, - .py-lg-9 { - padding-bottom: 90px !important; } - .pl-lg-9, - .px-lg-9 { - padding-left: 90px !important; } - .p-lg-10 { - padding: 100px !important; } - .pt-lg-10, - .py-lg-10 { - padding-top: 100px !important; } - .pr-lg-10, - .px-lg-10 { - padding-right: 100px !important; } - .pb-lg-10, - .py-lg-10 { - padding-bottom: 100px !important; } - .pl-lg-10, - .px-lg-10 { - padding-left: 100px !important; } - .p-lg-11 { - padding: 110px !important; } - .pt-lg-11, - .py-lg-11 { - padding-top: 110px !important; } - .pr-lg-11, - .px-lg-11 { - padding-right: 110px !important; } - .pb-lg-11, - .py-lg-11 { - padding-bottom: 110px !important; } - .pl-lg-11, - .px-lg-11 { - padding-left: 110px !important; } - .p-lg-12 { - padding: 120px !important; } - .pt-lg-12, - .py-lg-12 { - padding-top: 120px !important; } - .pr-lg-12, - .px-lg-12 { - padding-right: 120px !important; } - .pb-lg-12, - .py-lg-12 { - padding-bottom: 120px !important; } - .pl-lg-12, - .px-lg-12 { - padding-left: 120px !important; } - .p-lg-13 { - padding: 130px !important; } - .pt-lg-13, - .py-lg-13 { - padding-top: 130px !important; } - .pr-lg-13, - .px-lg-13 { - padding-right: 130px !important; } - .pb-lg-13, - .py-lg-13 { - padding-bottom: 130px !important; } - .pl-lg-13, - .px-lg-13 { - padding-left: 130px !important; } - .p-lg-14 { - padding: 140px !important; } - .pt-lg-14, - .py-lg-14 { - padding-top: 140px !important; } - .pr-lg-14, - .px-lg-14 { - padding-right: 140px !important; } - .pb-lg-14, - .py-lg-14 { - padding-bottom: 140px !important; } - .pl-lg-14, - .px-lg-14 { - padding-left: 140px !important; } - .p-lg-15 { - padding: 150px !important; } - .pt-lg-15, - .py-lg-15 { - padding-top: 150px !important; } - .pr-lg-15, - .px-lg-15 { - padding-right: 150px !important; } - .pb-lg-15, - .py-lg-15 { - padding-bottom: 150px !important; } - .pl-lg-15, - .px-lg-15 { - padding-left: 150px !important; } - .p-lg-16 { - padding: 160px !important; } - .pt-lg-16, - .py-lg-16 { - padding-top: 160px !important; } - .pr-lg-16, - .px-lg-16 { - padding-right: 160px !important; } - .pb-lg-16, - .py-lg-16 { - padding-bottom: 160px !important; } - .pl-lg-16, - .px-lg-16 { - padding-left: 160px !important; } - .p-lg-17 { - padding: 170px !important; } - .pt-lg-17, - .py-lg-17 { - padding-top: 170px !important; } - .pr-lg-17, - .px-lg-17 { - padding-right: 170px !important; } - .pb-lg-17, - .py-lg-17 { - padding-bottom: 170px !important; } - .pl-lg-17, - .px-lg-17 { - padding-left: 170px !important; } - .p-lg-18 { - padding: 180px !important; } - .pt-lg-18, - .py-lg-18 { - padding-top: 180px !important; } - .pr-lg-18, - .px-lg-18 { - padding-right: 180px !important; } - .pb-lg-18, - .py-lg-18 { - padding-bottom: 180px !important; } - .pl-lg-18, - .px-lg-18 { - padding-left: 180px !important; } - .p-lg-19 { - padding: 190px !important; } - .pt-lg-19, - .py-lg-19 { - padding-top: 190px !important; } - .pr-lg-19, - .px-lg-19 { - padding-right: 190px !important; } - .pb-lg-19, - .py-lg-19 { - padding-bottom: 190px !important; } - .pl-lg-19, - .px-lg-19 { - padding-left: 190px !important; } - .p-lg-20 { - padding: 200px !important; } - .pt-lg-20, - .py-lg-20 { - padding-top: 200px !important; } - .pr-lg-20, - .px-lg-20 { - padding-right: 200px !important; } - .pb-lg-20, - .py-lg-20 { - padding-bottom: 200px !important; } - .pl-lg-20, - .px-lg-20 { - padding-left: 200px !important; } - .m-lg-auto { - margin: auto !important; } - .mt-lg-auto, - .my-lg-auto { - margin-top: auto !important; } - .mr-lg-auto, - .mx-lg-auto { - margin-right: auto !important; } - .mb-lg-auto, - .my-lg-auto { - margin-bottom: auto !important; } - .ml-lg-auto, - .mx-lg-auto { - margin-left: auto !important; } } - -@media (min-width: 1300px) { - .m-xl-0 { - margin: 0 !important; } - .mt-xl-0, - .my-xl-0 { - margin-top: 0 !important; } - .mr-xl-0, - .mx-xl-0 { - margin-right: 0 !important; } - .mb-xl-0, - .my-xl-0 { - margin-bottom: 0 !important; } - .ml-xl-0, - .mx-xl-0 { - margin-left: 0 !important; } - .m-xl-1 { - margin: 10px !important; } - .mt-xl-1, - .my-xl-1 { - margin-top: 10px !important; } - .mr-xl-1, - .mx-xl-1 { - margin-right: 10px !important; } - .mb-xl-1, - .my-xl-1 { - margin-bottom: 10px !important; } - .ml-xl-1, - .mx-xl-1 { - margin-left: 10px !important; } - .m-xl-2 { - margin: 20px !important; } - .mt-xl-2, - .my-xl-2 { - margin-top: 20px !important; } - .mr-xl-2, - .mx-xl-2 { - margin-right: 20px !important; } - .mb-xl-2, - .my-xl-2 { - margin-bottom: 20px !important; } - .ml-xl-2, - .mx-xl-2 { - margin-left: 20px !important; } - .m-xl-3 { - margin: 30px !important; } - .mt-xl-3, - .my-xl-3 { - margin-top: 30px !important; } - .mr-xl-3, - .mx-xl-3 { - margin-right: 30px !important; } - .mb-xl-3, - .my-xl-3 { - margin-bottom: 30px !important; } - .ml-xl-3, - .mx-xl-3 { - margin-left: 30px !important; } - .m-xl-4 { - margin: 40px !important; } - .mt-xl-4, - .my-xl-4 { - margin-top: 40px !important; } - .mr-xl-4, - .mx-xl-4 { - margin-right: 40px !important; } - .mb-xl-4, - .my-xl-4 { - margin-bottom: 40px !important; } - .ml-xl-4, - .mx-xl-4 { - margin-left: 40px !important; } - .m-xl-5 { - margin: 50px !important; } - .mt-xl-5, - .my-xl-5 { - margin-top: 50px !important; } - .mr-xl-5, - .mx-xl-5 { - margin-right: 50px !important; } - .mb-xl-5, - .my-xl-5 { - margin-bottom: 50px !important; } - .ml-xl-5, - .mx-xl-5 { - margin-left: 50px !important; } - .m-xl-6 { - margin: 60px !important; } - .mt-xl-6, - .my-xl-6 { - margin-top: 60px !important; } - .mr-xl-6, - .mx-xl-6 { - margin-right: 60px !important; } - .mb-xl-6, - .my-xl-6 { - margin-bottom: 60px !important; } - .ml-xl-6, - .mx-xl-6 { - margin-left: 60px !important; } - .m-xl-7 { - margin: 70px !important; } - .mt-xl-7, - .my-xl-7 { - margin-top: 70px !important; } - .mr-xl-7, - .mx-xl-7 { - margin-right: 70px !important; } - .mb-xl-7, - .my-xl-7 { - margin-bottom: 70px !important; } - .ml-xl-7, - .mx-xl-7 { - margin-left: 70px !important; } - .m-xl-8 { - margin: 80px !important; } - .mt-xl-8, - .my-xl-8 { - margin-top: 80px !important; } - .mr-xl-8, - .mx-xl-8 { - margin-right: 80px !important; } - .mb-xl-8, - .my-xl-8 { - margin-bottom: 80px !important; } - .ml-xl-8, - .mx-xl-8 { - margin-left: 80px !important; } - .m-xl-9 { - margin: 90px !important; } - .mt-xl-9, - .my-xl-9 { - margin-top: 90px !important; } - .mr-xl-9, - .mx-xl-9 { - margin-right: 90px !important; } - .mb-xl-9, - .my-xl-9 { - margin-bottom: 90px !important; } - .ml-xl-9, - .mx-xl-9 { - margin-left: 90px !important; } - .m-xl-10 { - margin: 100px !important; } - .mt-xl-10, - .my-xl-10 { - margin-top: 100px !important; } - .mr-xl-10, - .mx-xl-10 { - margin-right: 100px !important; } - .mb-xl-10, - .my-xl-10 { - margin-bottom: 100px !important; } - .ml-xl-10, - .mx-xl-10 { - margin-left: 100px !important; } - .m-xl-11 { - margin: 110px !important; } - .mt-xl-11, - .my-xl-11 { - margin-top: 110px !important; } - .mr-xl-11, - .mx-xl-11 { - margin-right: 110px !important; } - .mb-xl-11, - .my-xl-11 { - margin-bottom: 110px !important; } - .ml-xl-11, - .mx-xl-11 { - margin-left: 110px !important; } - .m-xl-12 { - margin: 120px !important; } - .mt-xl-12, - .my-xl-12 { - margin-top: 120px !important; } - .mr-xl-12, - .mx-xl-12 { - margin-right: 120px !important; } - .mb-xl-12, - .my-xl-12 { - margin-bottom: 120px !important; } - .ml-xl-12, - .mx-xl-12 { - margin-left: 120px !important; } - .m-xl-13 { - margin: 130px !important; } - .mt-xl-13, - .my-xl-13 { - margin-top: 130px !important; } - .mr-xl-13, - .mx-xl-13 { - margin-right: 130px !important; } - .mb-xl-13, - .my-xl-13 { - margin-bottom: 130px !important; } - .ml-xl-13, - .mx-xl-13 { - margin-left: 130px !important; } - .m-xl-14 { - margin: 140px !important; } - .mt-xl-14, - .my-xl-14 { - margin-top: 140px !important; } - .mr-xl-14, - .mx-xl-14 { - margin-right: 140px !important; } - .mb-xl-14, - .my-xl-14 { - margin-bottom: 140px !important; } - .ml-xl-14, - .mx-xl-14 { - margin-left: 140px !important; } - .m-xl-15 { - margin: 150px !important; } - .mt-xl-15, - .my-xl-15 { - margin-top: 150px !important; } - .mr-xl-15, - .mx-xl-15 { - margin-right: 150px !important; } - .mb-xl-15, - .my-xl-15 { - margin-bottom: 150px !important; } - .ml-xl-15, - .mx-xl-15 { - margin-left: 150px !important; } - .m-xl-16 { - margin: 160px !important; } - .mt-xl-16, - .my-xl-16 { - margin-top: 160px !important; } - .mr-xl-16, - .mx-xl-16 { - margin-right: 160px !important; } - .mb-xl-16, - .my-xl-16 { - margin-bottom: 160px !important; } - .ml-xl-16, - .mx-xl-16 { - margin-left: 160px !important; } - .m-xl-17 { - margin: 170px !important; } - .mt-xl-17, - .my-xl-17 { - margin-top: 170px !important; } - .mr-xl-17, - .mx-xl-17 { - margin-right: 170px !important; } - .mb-xl-17, - .my-xl-17 { - margin-bottom: 170px !important; } - .ml-xl-17, - .mx-xl-17 { - margin-left: 170px !important; } - .m-xl-18 { - margin: 180px !important; } - .mt-xl-18, - .my-xl-18 { - margin-top: 180px !important; } - .mr-xl-18, - .mx-xl-18 { - margin-right: 180px !important; } - .mb-xl-18, - .my-xl-18 { - margin-bottom: 180px !important; } - .ml-xl-18, - .mx-xl-18 { - margin-left: 180px !important; } - .m-xl-19 { - margin: 190px !important; } - .mt-xl-19, - .my-xl-19 { - margin-top: 190px !important; } - .mr-xl-19, - .mx-xl-19 { - margin-right: 190px !important; } - .mb-xl-19, - .my-xl-19 { - margin-bottom: 190px !important; } - .ml-xl-19, - .mx-xl-19 { - margin-left: 190px !important; } - .m-xl-20 { - margin: 200px !important; } - .mt-xl-20, - .my-xl-20 { - margin-top: 200px !important; } - .mr-xl-20, - .mx-xl-20 { - margin-right: 200px !important; } - .mb-xl-20, - .my-xl-20 { - margin-bottom: 200px !important; } - .ml-xl-20, - .mx-xl-20 { - margin-left: 200px !important; } - .p-xl-0 { - padding: 0 !important; } - .pt-xl-0, - .py-xl-0 { - padding-top: 0 !important; } - .pr-xl-0, - .px-xl-0 { - padding-right: 0 !important; } - .pb-xl-0, - .py-xl-0 { - padding-bottom: 0 !important; } - .pl-xl-0, - .px-xl-0 { - padding-left: 0 !important; } - .p-xl-1 { - padding: 10px !important; } - .pt-xl-1, - .py-xl-1 { - padding-top: 10px !important; } - .pr-xl-1, - .px-xl-1 { - padding-right: 10px !important; } - .pb-xl-1, - .py-xl-1 { - padding-bottom: 10px !important; } - .pl-xl-1, - .px-xl-1 { - padding-left: 10px !important; } - .p-xl-2 { - padding: 20px !important; } - .pt-xl-2, - .py-xl-2 { - padding-top: 20px !important; } - .pr-xl-2, - .px-xl-2 { - padding-right: 20px !important; } - .pb-xl-2, - .py-xl-2 { - padding-bottom: 20px !important; } - .pl-xl-2, - .px-xl-2 { - padding-left: 20px !important; } - .p-xl-3 { - padding: 30px !important; } - .pt-xl-3, - .py-xl-3 { - padding-top: 30px !important; } - .pr-xl-3, - .px-xl-3 { - padding-right: 30px !important; } - .pb-xl-3, - .py-xl-3 { - padding-bottom: 30px !important; } - .pl-xl-3, - .px-xl-3 { - padding-left: 30px !important; } - .p-xl-4 { - padding: 40px !important; } - .pt-xl-4, - .py-xl-4 { - padding-top: 40px !important; } - .pr-xl-4, - .px-xl-4 { - padding-right: 40px !important; } - .pb-xl-4, - .py-xl-4 { - padding-bottom: 40px !important; } - .pl-xl-4, - .px-xl-4 { - padding-left: 40px !important; } - .p-xl-5 { - padding: 50px !important; } - .pt-xl-5, - .py-xl-5 { - padding-top: 50px !important; } - .pr-xl-5, - .px-xl-5 { - padding-right: 50px !important; } - .pb-xl-5, - .py-xl-5 { - padding-bottom: 50px !important; } - .pl-xl-5, - .px-xl-5 { - padding-left: 50px !important; } - .p-xl-6 { - padding: 60px !important; } - .pt-xl-6, - .py-xl-6 { - padding-top: 60px !important; } - .pr-xl-6, - .px-xl-6 { - padding-right: 60px !important; } - .pb-xl-6, - .py-xl-6 { - padding-bottom: 60px !important; } - .pl-xl-6, - .px-xl-6 { - padding-left: 60px !important; } - .p-xl-7 { - padding: 70px !important; } - .pt-xl-7, - .py-xl-7 { - padding-top: 70px !important; } - .pr-xl-7, - .px-xl-7 { - padding-right: 70px !important; } - .pb-xl-7, - .py-xl-7 { - padding-bottom: 70px !important; } - .pl-xl-7, - .px-xl-7 { - padding-left: 70px !important; } - .p-xl-8 { - padding: 80px !important; } - .pt-xl-8, - .py-xl-8 { - padding-top: 80px !important; } - .pr-xl-8, - .px-xl-8 { - padding-right: 80px !important; } - .pb-xl-8, - .py-xl-8 { - padding-bottom: 80px !important; } - .pl-xl-8, - .px-xl-8 { - padding-left: 80px !important; } - .p-xl-9 { - padding: 90px !important; } - .pt-xl-9, - .py-xl-9 { - padding-top: 90px !important; } - .pr-xl-9, - .px-xl-9 { - padding-right: 90px !important; } - .pb-xl-9, - .py-xl-9 { - padding-bottom: 90px !important; } - .pl-xl-9, - .px-xl-9 { - padding-left: 90px !important; } - .p-xl-10 { - padding: 100px !important; } - .pt-xl-10, - .py-xl-10 { - padding-top: 100px !important; } - .pr-xl-10, - .px-xl-10 { - padding-right: 100px !important; } - .pb-xl-10, - .py-xl-10 { - padding-bottom: 100px !important; } - .pl-xl-10, - .px-xl-10 { - padding-left: 100px !important; } - .p-xl-11 { - padding: 110px !important; } - .pt-xl-11, - .py-xl-11 { - padding-top: 110px !important; } - .pr-xl-11, - .px-xl-11 { - padding-right: 110px !important; } - .pb-xl-11, - .py-xl-11 { - padding-bottom: 110px !important; } - .pl-xl-11, - .px-xl-11 { - padding-left: 110px !important; } - .p-xl-12 { - padding: 120px !important; } - .pt-xl-12, - .py-xl-12 { - padding-top: 120px !important; } - .pr-xl-12, - .px-xl-12 { - padding-right: 120px !important; } - .pb-xl-12, - .py-xl-12 { - padding-bottom: 120px !important; } - .pl-xl-12, - .px-xl-12 { - padding-left: 120px !important; } - .p-xl-13 { - padding: 130px !important; } - .pt-xl-13, - .py-xl-13 { - padding-top: 130px !important; } - .pr-xl-13, - .px-xl-13 { - padding-right: 130px !important; } - .pb-xl-13, - .py-xl-13 { - padding-bottom: 130px !important; } - .pl-xl-13, - .px-xl-13 { - padding-left: 130px !important; } - .p-xl-14 { - padding: 140px !important; } - .pt-xl-14, - .py-xl-14 { - padding-top: 140px !important; } - .pr-xl-14, - .px-xl-14 { - padding-right: 140px !important; } - .pb-xl-14, - .py-xl-14 { - padding-bottom: 140px !important; } - .pl-xl-14, - .px-xl-14 { - padding-left: 140px !important; } - .p-xl-15 { - padding: 150px !important; } - .pt-xl-15, - .py-xl-15 { - padding-top: 150px !important; } - .pr-xl-15, - .px-xl-15 { - padding-right: 150px !important; } - .pb-xl-15, - .py-xl-15 { - padding-bottom: 150px !important; } - .pl-xl-15, - .px-xl-15 { - padding-left: 150px !important; } - .p-xl-16 { - padding: 160px !important; } - .pt-xl-16, - .py-xl-16 { - padding-top: 160px !important; } - .pr-xl-16, - .px-xl-16 { - padding-right: 160px !important; } - .pb-xl-16, - .py-xl-16 { - padding-bottom: 160px !important; } - .pl-xl-16, - .px-xl-16 { - padding-left: 160px !important; } - .p-xl-17 { - padding: 170px !important; } - .pt-xl-17, - .py-xl-17 { - padding-top: 170px !important; } - .pr-xl-17, - .px-xl-17 { - padding-right: 170px !important; } - .pb-xl-17, - .py-xl-17 { - padding-bottom: 170px !important; } - .pl-xl-17, - .px-xl-17 { - padding-left: 170px !important; } - .p-xl-18 { - padding: 180px !important; } - .pt-xl-18, - .py-xl-18 { - padding-top: 180px !important; } - .pr-xl-18, - .px-xl-18 { - padding-right: 180px !important; } - .pb-xl-18, - .py-xl-18 { - padding-bottom: 180px !important; } - .pl-xl-18, - .px-xl-18 { - padding-left: 180px !important; } - .p-xl-19 { - padding: 190px !important; } - .pt-xl-19, - .py-xl-19 { - padding-top: 190px !important; } - .pr-xl-19, - .px-xl-19 { - padding-right: 190px !important; } - .pb-xl-19, - .py-xl-19 { - padding-bottom: 190px !important; } - .pl-xl-19, - .px-xl-19 { - padding-left: 190px !important; } - .p-xl-20 { - padding: 200px !important; } - .pt-xl-20, - .py-xl-20 { - padding-top: 200px !important; } - .pr-xl-20, - .px-xl-20 { - padding-right: 200px !important; } - .pb-xl-20, - .py-xl-20 { - padding-bottom: 200px !important; } - .pl-xl-20, - .px-xl-20 { - padding-left: 200px !important; } - .m-xl-auto { - margin: auto !important; } - .mt-xl-auto, - .my-xl-auto { - margin-top: auto !important; } - .mr-xl-auto, - .mx-xl-auto { - margin-right: auto !important; } - .mb-xl-auto, - .my-xl-auto { - margin-bottom: auto !important; } - .ml-xl-auto, - .mx-xl-auto { - margin-left: auto !important; } } - -.text-justify { - text-align: justify !important; } - -.text-nowrap { - white-space: nowrap !important; } - -.text-truncate { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } - -.text-left { - text-align: left !important; } - -.text-right { - text-align: right !important; } - -.text-center { - text-align: center !important; } - -@media (min-width: 576px) { - .text-sm-left { - text-align: left !important; } - .text-sm-right { - text-align: right !important; } - .text-sm-center { - text-align: center !important; } } - -@media (min-width: 768px) { - .text-md-left { - text-align: left !important; } - .text-md-right { - text-align: right !important; } - .text-md-center { - text-align: center !important; } } - -@media (min-width: 992px) { - .text-lg-left { - text-align: left !important; } - .text-lg-right { - text-align: right !important; } - .text-lg-center { - text-align: center !important; } } - -@media (min-width: 1300px) { - .text-xl-left { - text-align: left !important; } - .text-xl-right { - text-align: right !important; } - .text-xl-center { - text-align: center !important; } } - -.text-lowercase { - text-transform: lowercase !important; } - -.text-uppercase { - text-transform: uppercase !important; } - -.text-capitalize { - text-transform: capitalize !important; } - -.font-weight-light { - font-weight: 300 !important; } - -.font-weight-normal { - font-weight: 400 !important; } - -.font-weight-bold { - font-weight: 400 !important; } - -.font-italic { - font-style: italic !important; } - -.text-white { - color: #fff !important; } - -.text-primary { - color: #1de9b6 !important; } - -a.text-primary:hover, a.text-primary:focus { - color: #13c095 !important; } - -.text-secondary { - color: #ffca28 !important; } - -a.text-secondary:hover, a.text-secondary:focus { - color: #f4b800 !important; } - -.text-success { - color: #28a745 !important; } - -a.text-success:hover, a.text-success:focus { - color: #1e7e34 !important; } - -.text-info { - color: #17a2b8 !important; } - -a.text-info:hover, a.text-info:focus { - color: #117a8b !important; } - -.text-warning { - color: #ffc107 !important; } - -a.text-warning:hover, a.text-warning:focus { - color: #d39e00 !important; } - -.text-danger { - color: #dc3545 !important; } - -a.text-danger:hover, a.text-danger:focus { - color: #bd2130 !important; } - -.text-light { - color: #f8f9fa !important; } - -a.text-light:hover, a.text-light:focus { - color: #dae0e5 !important; } - -.text-dark { - color: #343a40 !important; } - -a.text-dark:hover, a.text-dark:focus { - color: #1d2124 !important; } - -.text-muted { - color: #6c757d !important; } - -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; } - -.visible { - visibility: visible !important; } - -.invisible { - visibility: hidden !important; } - -.container { - width: 100%; - padding-right: 10px; - padding-left: 10px; - margin-right: auto; - margin-left: auto; } - @media (min-width: 576px) { - .container { - max-width: 540px; } } - @media (min-width: 768px) { - .container { - max-width: 720px; } } - @media (min-width: 992px) { - .container { - max-width: 960px; } } - @media (min-width: 1300px) { - .container { - max-width: 1140px; } } - -.container-fluid { - width: 100%; - padding-right: 10px; - padding-left: 10px; - margin-right: auto; - margin-left: auto; } - -.row { - display: flex; - flex-wrap: wrap; - margin-right: -10px; - margin-left: -10px; } - -.no-gutters { - margin-right: 0; - margin-left: 0; } - .no-gutters > .col, - .no-gutters > [class*="col-"] { - padding-right: 0; - padding-left: 0; } - -.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col, -.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm, -.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md, -.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg, -.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl, -.col-xl-auto { - position: relative; - width: 100%; - min-height: 1px; - padding-right: 10px; - padding-left: 10px; } - -.col { - flex-basis: 0; - flex-grow: 1; - max-width: 100%; } - -.col-auto { - flex: 0 0 auto; - width: auto; - max-width: none; } - -.col-1 { - flex: 0 0 8.33333333%; - max-width: 8.33333333%; } - -.col-2 { - flex: 0 0 16.66666667%; - max-width: 16.66666667%; } - -.col-3 { - flex: 0 0 25%; - max-width: 25%; } - -.col-4 { - flex: 0 0 33.33333333%; - max-width: 33.33333333%; } - -.col-5 { - flex: 0 0 41.66666667%; - max-width: 41.66666667%; } - -.col-6 { - flex: 0 0 50%; - max-width: 50%; } - -.col-7 { - flex: 0 0 58.33333333%; - max-width: 58.33333333%; } - -.col-8 { - flex: 0 0 66.66666667%; - max-width: 66.66666667%; } - -.col-9 { - flex: 0 0 75%; - max-width: 75%; } - -.col-10 { - flex: 0 0 83.33333333%; - max-width: 83.33333333%; } - -.col-11 { - flex: 0 0 91.66666667%; - max-width: 91.66666667%; } - -.col-12 { - flex: 0 0 100%; - max-width: 100%; } - -.order-first { - order: -1; } - -.order-last { - order: 13; } - -.order-0 { - order: 0; } - -.order-1 { - order: 1; } - -.order-2 { - order: 2; } - -.order-3 { - order: 3; } - -.order-4 { - order: 4; } - -.order-5 { - order: 5; } - -.order-6 { - order: 6; } - -.order-7 { - order: 7; } - -.order-8 { - order: 8; } - -.order-9 { - order: 9; } - -.order-10 { - order: 10; } - -.order-11 { - order: 11; } - -.order-12 { - order: 12; } - -.offset-1 { - margin-left: 8.33333333%; } - -.offset-2 { - margin-left: 16.66666667%; } - -.offset-3 { - margin-left: 25%; } - -.offset-4 { - margin-left: 33.33333333%; } - -.offset-5 { - margin-left: 41.66666667%; } - -.offset-6 { - margin-left: 50%; } - -.offset-7 { - margin-left: 58.33333333%; } - -.offset-8 { - margin-left: 66.66666667%; } - -.offset-9 { - margin-left: 75%; } - -.offset-10 { - margin-left: 83.33333333%; } - -.offset-11 { - margin-left: 91.66666667%; } - -@media (min-width: 576px) { - .col-sm { - flex-basis: 0; - flex-grow: 1; - max-width: 100%; } - .col-sm-auto { - flex: 0 0 auto; - width: auto; - max-width: none; } - .col-sm-1 { - flex: 0 0 8.33333333%; - max-width: 8.33333333%; } - .col-sm-2 { - flex: 0 0 16.66666667%; - max-width: 16.66666667%; } - .col-sm-3 { - flex: 0 0 25%; - max-width: 25%; } - .col-sm-4 { - flex: 0 0 33.33333333%; - max-width: 33.33333333%; } - .col-sm-5 { - flex: 0 0 41.66666667%; - max-width: 41.66666667%; } - .col-sm-6 { - flex: 0 0 50%; - max-width: 50%; } - .col-sm-7 { - flex: 0 0 58.33333333%; - max-width: 58.33333333%; } - .col-sm-8 { - flex: 0 0 66.66666667%; - max-width: 66.66666667%; } - .col-sm-9 { - flex: 0 0 75%; - max-width: 75%; } - .col-sm-10 { - flex: 0 0 83.33333333%; - max-width: 83.33333333%; } - .col-sm-11 { - flex: 0 0 91.66666667%; - max-width: 91.66666667%; } - .col-sm-12 { - flex: 0 0 100%; - max-width: 100%; } - .order-sm-first { - order: -1; } - .order-sm-last { - order: 13; } - .order-sm-0 { - order: 0; } - .order-sm-1 { - order: 1; } - .order-sm-2 { - order: 2; } - .order-sm-3 { - order: 3; } - .order-sm-4 { - order: 4; } - .order-sm-5 { - order: 5; } - .order-sm-6 { - order: 6; } - .order-sm-7 { - order: 7; } - .order-sm-8 { - order: 8; } - .order-sm-9 { - order: 9; } - .order-sm-10 { - order: 10; } - .order-sm-11 { - order: 11; } - .order-sm-12 { - order: 12; } - .offset-sm-0 { - margin-left: 0; } - .offset-sm-1 { - margin-left: 8.33333333%; } - .offset-sm-2 { - margin-left: 16.66666667%; } - .offset-sm-3 { - margin-left: 25%; } - .offset-sm-4 { - margin-left: 33.33333333%; } - .offset-sm-5 { - margin-left: 41.66666667%; } - .offset-sm-6 { - margin-left: 50%; } - .offset-sm-7 { - margin-left: 58.33333333%; } - .offset-sm-8 { - margin-left: 66.66666667%; } - .offset-sm-9 { - margin-left: 75%; } - .offset-sm-10 { - margin-left: 83.33333333%; } - .offset-sm-11 { - margin-left: 91.66666667%; } } - -@media (min-width: 768px) { - .col-md { - flex-basis: 0; - flex-grow: 1; - max-width: 100%; } - .col-md-auto { - flex: 0 0 auto; - width: auto; - max-width: none; } - .col-md-1 { - flex: 0 0 8.33333333%; - max-width: 8.33333333%; } - .col-md-2 { - flex: 0 0 16.66666667%; - max-width: 16.66666667%; } - .col-md-3 { - flex: 0 0 25%; - max-width: 25%; } - .col-md-4 { - flex: 0 0 33.33333333%; - max-width: 33.33333333%; } - .col-md-5 { - flex: 0 0 41.66666667%; - max-width: 41.66666667%; } - .col-md-6 { - flex: 0 0 50%; - max-width: 50%; } - .col-md-7 { - flex: 0 0 58.33333333%; - max-width: 58.33333333%; } - .col-md-8 { - flex: 0 0 66.66666667%; - max-width: 66.66666667%; } - .col-md-9 { - flex: 0 0 75%; - max-width: 75%; } - .col-md-10 { - flex: 0 0 83.33333333%; - max-width: 83.33333333%; } - .col-md-11 { - flex: 0 0 91.66666667%; - max-width: 91.66666667%; } - .col-md-12 { - flex: 0 0 100%; - max-width: 100%; } - .order-md-first { - order: -1; } - .order-md-last { - order: 13; } - .order-md-0 { - order: 0; } - .order-md-1 { - order: 1; } - .order-md-2 { - order: 2; } - .order-md-3 { - order: 3; } - .order-md-4 { - order: 4; } - .order-md-5 { - order: 5; } - .order-md-6 { - order: 6; } - .order-md-7 { - order: 7; } - .order-md-8 { - order: 8; } - .order-md-9 { - order: 9; } - .order-md-10 { - order: 10; } - .order-md-11 { - order: 11; } - .order-md-12 { - order: 12; } - .offset-md-0 { - margin-left: 0; } - .offset-md-1 { - margin-left: 8.33333333%; } - .offset-md-2 { - margin-left: 16.66666667%; } - .offset-md-3 { - margin-left: 25%; } - .offset-md-4 { - margin-left: 33.33333333%; } - .offset-md-5 { - margin-left: 41.66666667%; } - .offset-md-6 { - margin-left: 50%; } - .offset-md-7 { - margin-left: 58.33333333%; } - .offset-md-8 { - margin-left: 66.66666667%; } - .offset-md-9 { - margin-left: 75%; } - .offset-md-10 { - margin-left: 83.33333333%; } - .offset-md-11 { - margin-left: 91.66666667%; } } - -@media (min-width: 992px) { - .col-lg { - flex-basis: 0; - flex-grow: 1; - max-width: 100%; } - .col-lg-auto { - flex: 0 0 auto; - width: auto; - max-width: none; } - .col-lg-1 { - flex: 0 0 8.33333333%; - max-width: 8.33333333%; } - .col-lg-2 { - flex: 0 0 16.66666667%; - max-width: 16.66666667%; } - .col-lg-3 { - flex: 0 0 25%; - max-width: 25%; } - .col-lg-4 { - flex: 0 0 33.33333333%; - max-width: 33.33333333%; } - .col-lg-5 { - flex: 0 0 41.66666667%; - max-width: 41.66666667%; } - .col-lg-6 { - flex: 0 0 50%; - max-width: 50%; } - .col-lg-7 { - flex: 0 0 58.33333333%; - max-width: 58.33333333%; } - .col-lg-8 { - flex: 0 0 66.66666667%; - max-width: 66.66666667%; } - .col-lg-9 { - flex: 0 0 75%; - max-width: 75%; } - .col-lg-10 { - flex: 0 0 83.33333333%; - max-width: 83.33333333%; } - .col-lg-11 { - flex: 0 0 91.66666667%; - max-width: 91.66666667%; } - .col-lg-12 { - flex: 0 0 100%; - max-width: 100%; } - .order-lg-first { - order: -1; } - .order-lg-last { - order: 13; } - .order-lg-0 { - order: 0; } - .order-lg-1 { - order: 1; } - .order-lg-2 { - order: 2; } - .order-lg-3 { - order: 3; } - .order-lg-4 { - order: 4; } - .order-lg-5 { - order: 5; } - .order-lg-6 { - order: 6; } - .order-lg-7 { - order: 7; } - .order-lg-8 { - order: 8; } - .order-lg-9 { - order: 9; } - .order-lg-10 { - order: 10; } - .order-lg-11 { - order: 11; } - .order-lg-12 { - order: 12; } - .offset-lg-0 { - margin-left: 0; } - .offset-lg-1 { - margin-left: 8.33333333%; } - .offset-lg-2 { - margin-left: 16.66666667%; } - .offset-lg-3 { - margin-left: 25%; } - .offset-lg-4 { - margin-left: 33.33333333%; } - .offset-lg-5 { - margin-left: 41.66666667%; } - .offset-lg-6 { - margin-left: 50%; } - .offset-lg-7 { - margin-left: 58.33333333%; } - .offset-lg-8 { - margin-left: 66.66666667%; } - .offset-lg-9 { - margin-left: 75%; } - .offset-lg-10 { - margin-left: 83.33333333%; } - .offset-lg-11 { - margin-left: 91.66666667%; } } - -@media (min-width: 1300px) { - .col-xl { - flex-basis: 0; - flex-grow: 1; - max-width: 100%; } - .col-xl-auto { - flex: 0 0 auto; - width: auto; - max-width: none; } - .col-xl-1 { - flex: 0 0 8.33333333%; - max-width: 8.33333333%; } - .col-xl-2 { - flex: 0 0 16.66666667%; - max-width: 16.66666667%; } - .col-xl-3 { - flex: 0 0 25%; - max-width: 25%; } - .col-xl-4 { - flex: 0 0 33.33333333%; - max-width: 33.33333333%; } - .col-xl-5 { - flex: 0 0 41.66666667%; - max-width: 41.66666667%; } - .col-xl-6 { - flex: 0 0 50%; - max-width: 50%; } - .col-xl-7 { - flex: 0 0 58.33333333%; - max-width: 58.33333333%; } - .col-xl-8 { - flex: 0 0 66.66666667%; - max-width: 66.66666667%; } - .col-xl-9 { - flex: 0 0 75%; - max-width: 75%; } - .col-xl-10 { - flex: 0 0 83.33333333%; - max-width: 83.33333333%; } - .col-xl-11 { - flex: 0 0 91.66666667%; - max-width: 91.66666667%; } - .col-xl-12 { - flex: 0 0 100%; - max-width: 100%; } - .order-xl-first { - order: -1; } - .order-xl-last { - order: 13; } - .order-xl-0 { - order: 0; } - .order-xl-1 { - order: 1; } - .order-xl-2 { - order: 2; } - .order-xl-3 { - order: 3; } - .order-xl-4 { - order: 4; } - .order-xl-5 { - order: 5; } - .order-xl-6 { - order: 6; } - .order-xl-7 { - order: 7; } - .order-xl-8 { - order: 8; } - .order-xl-9 { - order: 9; } - .order-xl-10 { - order: 10; } - .order-xl-11 { - order: 11; } - .order-xl-12 { - order: 12; } - .offset-xl-0 { - margin-left: 0; } - .offset-xl-1 { - margin-left: 8.33333333%; } - .offset-xl-2 { - margin-left: 16.66666667%; } - .offset-xl-3 { - margin-left: 25%; } - .offset-xl-4 { - margin-left: 33.33333333%; } - .offset-xl-5 { - margin-left: 41.66666667%; } - .offset-xl-6 { - margin-left: 50%; } - .offset-xl-7 { - margin-left: 58.33333333%; } - .offset-xl-8 { - margin-left: 66.66666667%; } - .offset-xl-9 { - margin-left: 75%; } - .offset-xl-10 { - margin-left: 83.33333333%; } - .offset-xl-11 { - margin-left: 91.66666667%; } } - -.table, .content table { - width: 100%; - max-width: 100%; - margin-bottom: 1rem; - background-color: transparent; } - .table th, .content table th, - .table td, - .content table td { - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid #dee2e6; } - .table thead th, .content table thead th { - vertical-align: bottom; - border-bottom: 2px solid #dee2e6; } - .table tbody + tbody, .content table tbody + tbody { - border-top: 2px solid #dee2e6; } - .table .table, .content table .table, .table .content table, .content .table table, .content table table { - background-color: #fff; } - -.table-sm th, -.table-sm td { - padding: 0.3rem; } - -.table-bordered { - border: 1px solid #dee2e6; } - .table-bordered th, - .table-bordered td { - border: 1px solid #dee2e6; } - .table-bordered thead th, - .table-bordered thead td { - border-bottom-width: 2px; } - -.table-striped tbody tr:nth-of-type(odd) { - background-color: rgba(33, 37, 41, 0.05); } - -.table-hover tbody tr:hover { - background-color: rgba(33, 37, 41, 0.075); } - -.table-primary, -.table-primary > th, -.table-primary > td { - background-color: #c0f9eb; } - -.table-hover .table-primary:hover { - background-color: #a9f7e4; } - .table-hover .table-primary:hover > td, - .table-hover .table-primary:hover > th { - background-color: #a9f7e4; } - -.table-secondary, -.table-secondary > th, -.table-secondary > td { - background-color: #fff0c3; } - -.table-hover .table-secondary:hover { - background-color: #ffeaaa; } - .table-hover .table-secondary:hover > td, - .table-hover .table-secondary:hover > th { - background-color: #ffeaaa; } - -.table-success, -.table-success > th, -.table-success > td { - background-color: #c3e6cb; } - -.table-hover .table-success:hover { - background-color: #b1dfbb; } - .table-hover .table-success:hover > td, - .table-hover .table-success:hover > th { - background-color: #b1dfbb; } - -.table-info, -.table-info > th, -.table-info > td { - background-color: #bee5eb; } - -.table-hover .table-info:hover { - background-color: #abdde5; } - .table-hover .table-info:hover > td, - .table-hover .table-info:hover > th { - background-color: #abdde5; } - -.table-warning, -.table-warning > th, -.table-warning > td { - background-color: #ffeeba; } - -.table-hover .table-warning:hover { - background-color: #ffe8a1; } - .table-hover .table-warning:hover > td, - .table-hover .table-warning:hover > th { - background-color: #ffe8a1; } - -.table-danger, -.table-danger > th, -.table-danger > td { - background-color: #f5c6cb; } - -.table-hover .table-danger:hover { - background-color: #f1b0b7; } - .table-hover .table-danger:hover > td, - .table-hover .table-danger:hover > th { - background-color: #f1b0b7; } - -.table-light, -.table-light > th, -.table-light > td { - background-color: #fdfdfe; } - -.table-hover .table-light:hover { - background-color: #ececf6; } - .table-hover .table-light:hover > td, - .table-hover .table-light:hover > th { - background-color: #ececf6; } - -.table-dark, -.table-dark > th, -.table-dark > td { - background-color: #c6c8ca; } - -.table-hover .table-dark:hover { - background-color: #b9bbbe; } - .table-hover .table-dark:hover > td, - .table-hover .table-dark:hover > th { - background-color: #b9bbbe; } - -.table-active, -.table-active > th, -.table-active > td { - background-color: rgba(33, 37, 41, 0.075); } - -.table-hover .table-active:hover { - background-color: rgba(22, 24, 27, 0.075); } - .table-hover .table-active:hover > td, - .table-hover .table-active:hover > th { - background-color: rgba(22, 24, 27, 0.075); } - -.table .thead-dark th, .content table .thead-dark th { - color: #fff; - background-color: #212529; - border-color: #32383e; } - -.table .thead-light th, .content table .thead-light th { - color: #495057; - background-color: #e9ecef; - border-color: #dee2e6; } - -.table-dark { - color: #fff; - background-color: #212529; } - .table-dark th, - .table-dark td, - .table-dark thead th { - border-color: #32383e; } - .table-dark.table-bordered { - border: 0; } - .table-dark.table-striped tbody tr:nth-of-type(odd) { - background-color: rgba(255, 255, 255, 0.05); } - .table-dark.table-hover tbody tr:hover { - background-color: rgba(255, 255, 255, 0.075); } - -@media (max-width: 575.98px) { - .table-responsive-sm { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; } - .table-responsive-sm > .table-bordered { - border: 0; } } - -@media (max-width: 767.98px) { - .table-responsive-md { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; } - .table-responsive-md > .table-bordered { - border: 0; } } - -@media (max-width: 991.98px) { - .table-responsive-lg { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; } - .table-responsive-lg > .table-bordered { - border: 0; } } - -@media (max-width: 1299.98px) { - .table-responsive-xl { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; } - .table-responsive-xl > .table-bordered { - border: 0; } } - -.table-responsive { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; } - .table-responsive > .table-bordered { - border: 0; } - -/*! - * Hamburgers - * @description Tasty CSS-animated hamburgers - * @author Jonathan Suh @jonsuh - * @site https://jonsuh.com/hamburgers - * @link https://github.com/jonsuh/hamburgers - */ -.hamburger { - padding: 15px 15px; - display: inline-block; - cursor: pointer; - transition-property: opacity, filter; - transition-duration: 0.15s; - transition-timing-function: linear; - font: inherit; - color: inherit; - text-transform: none; - background-color: transparent; - border: 0; - margin: 0; - overflow: visible; } - .hamburger:hover { - opacity: 0.7; } - .hamburger.is-active:hover { - opacity: 0.7; } - .hamburger.is-active .hamburger-inner, - .hamburger.is-active .hamburger-inner::before, - .hamburger.is-active .hamburger-inner::after { - background-color: #FFF; } - -.hamburger-box { - width: 32px; - height: 19px; - display: inline-block; - position: relative; } - -.hamburger-inner { - display: block; - top: 50%; - margin-top: -1.5px; } - .hamburger-inner, .hamburger-inner::before, .hamburger-inner::after { - width: 32px; - height: 3px; - background-color: #1de9b6; - border-radius: 3px; - position: absolute; - transition-property: transform; - transition-duration: 0.15s; - transition-timing-function: ease; } - .hamburger-inner::before, .hamburger-inner::after { - content: ""; - display: block; } - .hamburger-inner::before { - top: -8px; } - .hamburger-inner::after { - bottom: -8px; } - -/* - * Slider - */ -.hamburger--slider .hamburger-inner { - top: 1.5px; } - .hamburger--slider .hamburger-inner::before { - top: 8px; - transition-property: transform, opacity; - transition-timing-function: ease; - transition-duration: 0.15s; } - .hamburger--slider .hamburger-inner::after { - top: 16px; } - -.hamburger--slider.is-active .hamburger-inner { - transform: translate3d(0, 8px, 0) rotate(45deg); } - .hamburger--slider.is-active .hamburger-inner::before { - transform: rotate(-45deg) translate3d(-4.57142857px, -5px, 0); - opacity: 0; } - .hamburger--slider.is-active .hamburger-inner::after { - transform: translate3d(0, -16px, 0) rotate(-90deg); } - -.highlight { - background: #f5f5f5; } - -.highlight .hll { - background-color: #ffffcc; } - -.highlight .c { - color: #999988; - font-style: italic; } - -/* Comment */ -.highlight .err { - color: #a61717; - background-color: #e3d2d2; } - -/* Error */ -.highlight .k { - color: #000000; - font-weight: bold; } - -/* Keyword */ -.highlight .o { - color: #000000; - font-weight: bold; } - -/* Operator */ -.highlight .cm { - color: #999988; - font-style: italic; } - -/* Comment.Multiline */ -.highlight .cp { - color: #999999; - font-weight: bold; - font-style: italic; } - -/* Comment.Preproc */ -.highlight .c1 { - color: #999988; - font-style: italic; } - -/* Comment.Single */ -.highlight .cs { - color: #999999; - font-weight: bold; - font-style: italic; } - -/* Comment.Special */ -.highlight .gd { - color: #000000; - background-color: #ffdddd; } - -/* Generic.Deleted */ -.highlight .ge { - color: #000000; - font-style: italic; } - -/* Generic.Emph */ -.highlight .gr { - color: #aa0000; } - -/* Generic.Error */ -.highlight .gh { - color: #999999; } - -/* Generic.Heading */ -.highlight .gi { - color: #000000; - background-color: #ddffdd; } - -/* Generic.Inserted */ -.highlight .go { - color: #888888; } - -/* Generic.Output */ -.highlight .gp { - color: #555555; } - -/* Generic.Prompt */ -.highlight .gs { - font-weight: bold; } - -/* Generic.Strong */ -.highlight .gu { - color: #aaaaaa; } - -/* Generic.Subheading */ -.highlight .gt { - color: #aa0000; } - -/* Generic.Traceback */ -.highlight .kc { - color: #000000; - font-weight: bold; } - -/* Keyword.Constant */ -.highlight .kd { - color: #000000; - font-weight: bold; } - -/* Keyword.Declaration */ -.highlight .kn { - color: #000000; - font-weight: bold; } - -/* Keyword.Namespace */ -.highlight .kp { - color: #000000; - font-weight: bold; } - -/* Keyword.Pseudo */ -.highlight .kr { - color: #000000; - font-weight: bold; } - -/* Keyword.Reserved */ -.highlight .kt { - color: #445588; - font-weight: bold; } - -/* Keyword.Type */ -.highlight .m { - color: #009999; } - -/* Literal.Number */ -.highlight .s { - color: #d01040; } - -/* Literal.String */ -.highlight .na { - color: #008080; } - -/* Name.Attribute */ -.highlight .nb { - color: #0086B3; } - -/* Name.Builtin */ -.highlight .nc { - color: #445588; - font-weight: bold; } - -/* Name.Class */ -.highlight .no { - color: #008080; } - -/* Name.Constant */ -.highlight .nd { - color: #3c5d5d; - font-weight: bold; } - -/* Name.Decorator */ -.highlight .ni { - color: #800080; } - -/* Name.Entity */ -.highlight .ne { - color: #990000; - font-weight: bold; } - -/* Name.Exception */ -.highlight .nf { - color: #990000; - font-weight: bold; } - -/* Name.Function */ -.highlight .nl { - color: #990000; - font-weight: bold; } - -/* Name.Label */ -.highlight .nn { - color: #555555; } - -/* Name.Namespace */ -.highlight .nt { - color: #000080; } - -/* Name.Tag */ -.highlight .nv { - color: #008080; } - -/* Name.Variable */ -.highlight .ow { - color: #000000; - font-weight: bold; } - -/* Operator.Word */ -.highlight .w { - color: #bbbbbb; } - -/* Text.Whitespace */ -.highlight .mf { - color: #009999; } - -/* Literal.Number.Float */ -.highlight .mh { - color: #009999; } - -/* Literal.Number.Hex */ -.highlight .mi { - color: #009999; } - -/* Literal.Number.Integer */ -.highlight .mo { - color: #009999; } - -/* Literal.Number.Oct */ -.highlight .sb { - color: #d01040; } - -/* Literal.String.Backtick */ -.highlight .sc { - color: #d01040; } - -/* Literal.String.Char */ -.highlight .sd { - color: #d01040; } - -/* Literal.String.Doc */ -.highlight .s2 { - color: #d01040; } - -/* Literal.String.Double */ -.highlight .se { - color: #d01040; } - -/* Literal.String.Escape */ -.highlight .sh { - color: #d01040; } - -/* Literal.String.Heredoc */ -.highlight .si { - color: #d01040; } - -/* Literal.String.Interpol */ -.highlight .sx { - color: #d01040; } - -/* Literal.String.Other */ -.highlight .sr { - color: #009926; } - -/* Literal.String.Regex */ -.highlight .s1 { - color: #d01040; } - -/* Literal.String.Single */ -.highlight .ss { - color: #990073; } - -/* Literal.String.Symbol */ -.highlight .bp { - color: #999999; } - -/* Name.Builtin.Pseudo */ -.highlight .vc { - color: #008080; } - -/* Name.Variable.Class */ -.highlight .vg { - color: #008080; } - -/* Name.Variable.Global */ -.highlight .vi { - color: #008080; } - -/* Name.Variable.Instance */ -.highlight .il { - color: #009999; } - -/* Literal.Number.Integer.Long */ -ul, -ol { - margin: 0; - padding: 0; - list-style: none; } - -p { - font-family: "Roboto", Arial, sans-serif, -apple-system; - font-size: 1rem; - line-height: 1.4; - color: #383f45; - font-weight: 400; } - -.page { - display: flex; - min-height: 100vh; - flex-direction: column; } - .page .wrapper { - flex: 1; } - -.header { - color: #1de9b6; - background-color: #ffffff; - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px 0 10px 0; } - .header .container { - display: flex; - justify-content: space-between; - align-items: center; } - .header.header-absolute { - position: absolute; - z-index: 10; - width: 100%; } - -.lock-scroll .header.header-absolute { - position: static; } - -.footer { - background: #eaeaea; - padding-top: 20px; - padding-bottom: 20px; } - .footer .footer-inner { - display: flex; - justify-content: space-between; - flex-direction: column; - align-items: flex-start; } - @media (min-width: 576px) { - .footer .footer-inner { - justify-content: space-between; - flex-direction: row; - align-items: center; } } - .footer .footer-title { - color: #ffffff; - font-size: 1.3rem; - font-family: "Lora", Arial, sans-serif, -apple-system; - margin-bottom: 10px; - flex: 0; } - @media (min-width: 576px) { - .footer .footer-title { - margin: 0; - flex: 0 0 120px; } } - .footer ul.footer-menu { - list-style: none; - margin: 0; - padding: 0; - flex: 1; } - .footer ul.footer-menu li { - display: block; - margin-right: 10px; - color: #333; - font-size: 0.9rem; - line-height: 1.8; } - .footer ul.footer-menu li:last-of-type { - margin-right: 0; } - .footer ul.footer-menu li a { - color: #333; - text-decoration: none; } - .footer ul.footer-menu li a:hover { - text-decoration: underline; } - .footer ul.footer-menu li.copyright { - font-weight: bold; - color: #333; - display: none; } - @media (min-width: 768px) { - .footer ul.footer-menu li.copyright { - display: inline-block; } } - @media (min-width: 576px) { - .footer ul.footer-menu { - height: inherit; - display: flex; - list-style: none; - margin: 0; - padding: 0; - align-items: center; - justify-content: flex-end; } - .footer ul.footer-menu li { - list-style: none; } - .footer ul.footer-menu li a { - display: inline-block; - height: 40px; - padding: 10px 8px 10px 8px; - font-weight: 300; } } - -.sub-footer { - background: #f4f5fb; - padding-top: 20px; - padding-bottom: 20px; } - @media (min-width: 768px) { - .sub-footer { - padding-top: 10px; - padding-bottom: 10px; } } - .sub-footer .sub-footer-inner { - display: flex; - flex-direction: column; - justify-content: flex-end; } - @media (min-width: 768px) { - .sub-footer .sub-footer-inner { - flex-direction: row; } } - .sub-footer .sub-footer-inner ul { - list-style: none; - margin: 0; - padding: 0; } - .sub-footer .sub-footer-inner ul li { - list-style: none; - display: block; - color: #333; - font-size: 0.9rem; - line-height: 1.8; - font-weight: bold; } - .sub-footer .sub-footer-inner ul li strong { - font-weight: bold; - color: #ffffff; } - .sub-footer .sub-footer-inner ul li a { - color: #333; - text-decoration: none; } - .sub-footer .sub-footer-inner ul li a:hover { - text-decoration: underline; } - .sub-footer .sub-footer-inner ul li span { - display: inline-block; - height: 40px; - padding: 10px 0 10px 8px; - font-weight: bold; - color: #ffffff; } - .sub-footer .sub-footer-inner ul li.zerostatic a { - color: #333; } - @media (min-width: 576px) { - .sub-footer .sub-footer-inner ul li { - display: inline-block; - margin-left: 10px; } - .sub-footer .sub-footer-inner ul li:first-of-type { - margin-left: 0; } } - -.logo { - display: none; } - @media (min-width: 576px) { - .logo { - display: block; - width: 70px; } } - .logo img { - width: 100%; - height: auto; } - .logo a { - display: block; - width: 100%; - height: 100%; } - -.logo-mobile { - display: block; - width: 54px; } - @media (min-width: 576px) { - .logo-mobile { - display: none; } } - .logo-mobile img { - width: 100%; - height: auto; } - .logo-mobile a { - display: block; - width: 100%; - height: 100%; } - -.main-menu { - display: none; } - @media (min-width: 768px) { - .main-menu { - display: block; } } - .main-menu > ul { - display: flex; - align-items: center; - justify-content: flex-start; - font-family: "Roboto", Arial, sans-serif, -apple-system; } - .main-menu > ul > li { - list-style: none; - font-size: 14px; } - .main-menu > ul > li > a { - padding: 10px 14px 10px 14px; - display: inline-block; - font-weight: normal; - text-decoration: none; - color: #1de9b6; } - .main-menu > ul > li > a:hover { - text-decoration: underline; - color: #1de9b6; } - .main-menu > ul > li.active > a { - font-weight: bold; } - -.main-menu-mobile { - position: fixed; - background: #1de9b6; - top: 0; - left: 0; - width: 100%; - height: 100vh; - opacity: 0; - visibility: hidden; - transition: opacity 0.35s, visibility 0.35s, height 0.35s; - overflow: hidden; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; } - .main-menu-mobile.open { - opacity: 0.9; - visibility: visible; - height: 100%; - z-index: 20; } - .main-menu-mobile.open li { - animation: fadeInRight 0.5s ease forwards; - animation-delay: 0.35s; } - .main-menu-mobile.open li:nth-of-type(2) { - animation-delay: 0.4s; } - .main-menu-mobile.open li:nth-of-type(3) { - animation-delay: 0.45s; } - .main-menu-mobile.open li:nth-of-type(4) { - animation-delay: 0.5s; } - .main-menu-mobile.open li:nth-of-type(5) { - animation-delay: 0.55s; } - .main-menu-mobile.open li:nth-of-type(6) { - animation-delay: 0.6s; } - .main-menu-mobile ul { - font-size: 2rem; - font-family: "Roboto", Arial, sans-serif, -apple-system; - text-align: center; - list-style: none; - padding: 0; - margin: 0; - flex: 0; } - .main-menu-mobile ul li { - display: block; - position: relative; - opacity: 0; } - .main-menu-mobile ul li a { - display: block; - position: relative; - color: #ffffff; - text-decoration: none; - overflow: hidden; - font-weight: lighter; } - .main-menu-mobile ul li a:hover::after, .main-menu-mobile ul li a:focus::after, .main-menu-mobile ul li a:active::after { - width: 100%; } - .main-menu-mobile ul li a::after { - content: ''; - position: absolute; - bottom: 0; - left: 50%; - width: 0%; - transform: translateX(-50%); - height: 3px; - background: #ffffff; - transition: 0.35s; } - -@keyframes fadeInRight { - 0% { - opacity: 0; - left: 20%; } - 100% { - opacity: 1; - left: 0; } } - -.lock-scroll { - overflow: hidden; } - -.docs-menu h4 { - font-size: 1rem; - font-weight: bold; } - -.docs-menu ul { - list-style: none; - padding: 0; - margin: 0; } - .docs-menu ul li { - font-size: 0.9rem; - line-height: 1.4; - font-weight: 400; - margin: 0; - padding: 4px 0 4px 0; } - .docs-menu ul li.active a { - color: #4beec5; - font-weight: 400; } - .docs-menu ul li a { - color: #212529; } - .docs-menu ul li a:hover { - color: #1de9b6; } - -.hamburger { - padding: 10px 0 10px 10px; - outline: none; - z-index: 30; - cursor: pointer; } - @media (min-width: 768px) { - .hamburger { - display: none; } } - .hamburger:focus { - outline: none; } - .hamburger .hamburger-inner, - .hamburger .hamburger-inner::before, - .hamburger .hamburger-inner::after { - background: #1de9b6; } - .hamburger .hamburger-inner::after { - width: 18px; - right: 0; } - .hamburger.is-active .hamburger-inner::after { - width: inherit; - right: unset; } - -.button { - white-space: nowrap; - display: inline-block; - padding: 8px 15px 6px 15px; - background: #1de9b6; - font-weight: normal; - text-transform: uppercase; - color: white; - text-decoration: none; - -webkit-transition: all 0.15s ease; - transition: all 0.15s ease; - border-radius: 3px; } - .button:hover { - color: #fff; - background-color: #4beec5; - text-decoration: none; } - -.button-white { - background: none; - color: #fff; - border: 2px solid #fff; } - -.title { - font-size: 2.7rem; - line-height: 1.1; - font-family: "Roboto", Arial, sans-serif, -apple-system; - letter-spacing: -0.2px; - font-weight: 100; - margin-bottom: 20px; } - @media (min-width: 768px) { - .title { - font-size: 3rem; - margin-bottom: 30px; } } - -.title-summary { - font-size: 1.6rem; - line-height: 1.4; - font-family: "Roboto", Arial, sans-serif, -apple-system; - letter-spacing: -0.2px; - font-weight: 200; - margin-bottom: 10px; } - @media (min-width: 768px) { - .title-summary { - font-size: 1.6rem; } } - -.content { - -webkit-font-smoothing: antialiased; } - .content .highlight { - border-radius: 2px; - margin-bottom: 20px; } - .content code { - background: #f5f5f5; - padding: 3px 6px; - border-radius: 3px; - font-family: "Roboto Mono", monospace; - font-size: 0.9rem; - line-height: 1.4; } - .content pre { - font-family: "Roboto Mono", monospace; - font-size: 0.9rem; - line-height: 1.4; - margin: 0; - padding: 10px; - border-radius: 1px; } - .content pre code { - font-family: "Roboto Mono", monospace; - font-size: 0.9rem; - line-height: 1.4; - border-radius: none; - padding: 0; - margin: 0; - background: none; } - .content strong { - font-weight: bold; } - .content em { - font-style: italic; - font-weight: normal; } - .content ol { - margin-top: 10px; - margin-bottom: 20px; - list-style-type: decimal; } - .content ol li { - margin-bottom: 5px; - margin-left: 20px; } - .content ul { - margin-top: 10px; - margin-bottom: 20px; - list-style-type: disc; } - .content ul li { - margin-bottom: 5px; - margin-left: 20px; } - .content a { - text-decoration: underline; } - .content p { - font-family: "Roboto", Arial, sans-serif, -apple-system; - font-size: 1rem; - line-height: 1.4; - color: #383f45; - font-weight: 400; } - .content h1 { - font-family: "Roboto", Arial, sans-serif, -apple-system; - font-size: 2.6rem; - line-height: 1.4; - font-weight: 300; - margin-bottom: 20px; } - .content h2 { - font-size: 2.2rem; - line-height: 1.4; - font-weight: 300; - letter-spacing: -0.01em; - font-family: "Roboto", Arial, sans-serif, -apple-system; - margin-bottom: 20px; } - .content h3 { - font-size: 1.6rem; - line-height: 1.4; - font-weight: 400; - font-family: "Roboto", Arial, sans-serif, -apple-system; - margin-bottom: 20px; } - .content h4 { - font-size: 1.5rem; - line-height: 1.4; - font-weight: 500; - font-family: "Roboto", Arial, sans-serif, -apple-system; - margin-bottom: 20px; } - .content h5 { - font-size: 1.4rem; - line-height: 1.4; - font-weight: 600; - font-family: "Roboto", Arial, sans-serif, -apple-system; - margin-bottom: 20px; } - .content h6 { - font-size: 1.2rem; - line-height: 1.4; - font-weight: 700; - font-family: "Roboto", Arial, sans-serif, -apple-system; - margin-bottom: 20px; } - .content blockquote { - background: #f9f9f9; - border-left: 10px solid #ccc; - margin: 1.5em 10px; - padding: 0.5em 10px; - quotes: "“" "”" "‘" "’"; } - .content blockquote:before { - color: #ccc; - content: open-quote; - font-size: 4em; - line-height: 0.1em; - margin-right: 0.25em; - vertical-align: -0.4em; } - .content blockquote p { - display: inline; } - .content img { - max-width: 100%; - height: auto; } - -.strip { - background-repeat: no-repeat; } - -.strip-white { - background-color: white; } - -.strip-grey { - background-color: #f4f5fb; } - -.strip-diagonal { - transform: skewY(5deg); - padding-bottom: 50px; - margin-bottom: 65px; } - .strip-diagonal > div { - transform: skewY(-5deg); } - -.strip-primary-gradient { - background-image: linear-gradient(to right, #1de9b6, #ffca28); } - -.strip-primary-gradient-top-bottom { - background-image: linear-gradient(to bottom, #1de9b6, #ffca28); } - -.strip-primary { - background-color: #1de9b6; } - -.strip-secondary { - background-color: #ffca28; } - -.strip-diagonal-right { - margin-top: -100px; - transform: skewY(-5deg); - padding-bottom: 100px; } - .strip-diagonal-right > div { - transform: skewY(5deg); } - -.strip-diagonal-left { - margin-top: -100px; - transform: skewY(5deg); - padding-bottom: 100px; } - .strip-diagonal-left > div { - transform: skewY(-5deg); } - -.strip-bg-contain { - background-size: contain; } - -.strip-bg-cover { - background-size: cover; } - -.whitebox { - border: 1px solid #dcdcdc; - border-radius: 3px; - box-shadow: 0 1px 18px rgba(0, 0, 0, 0.2); - background: #ffffff; - padding: 10px; } - -.overview { - background: lightgoldenrodyellow; - border-radius: 3px; - padding: 4px 10px 4px 10px; - float: right; } - -.page-home { - text-align: center; } - .page-home .title { - font-weight: lighter; - font-family: "Roboto", Arial, sans-serif, -apple-system; } - .page-home p { - margin: 0 auto; - font-size: 1.2rem; - font-weight: lighter; - margin-bottom: 40px; } - @media (min-width: 768px) { - .page-home p { - width: 80%; } } - @media (min-width: 992px) { - .page-home p { - width: 60%; } } - .page-home .terminal { - border-radius: 3px; - margin: 0 auto; - margin-top: -200px; } - .page-home .terminal img { - width: 100%; - height: auto; } - -body { - font-family: "Roboto", Arial, sans-serif, -apple-system; - font-size: 1rem; - font-weight: 400; - line-height: 1.4; - color: #212529; } - -.container { - padding-left: 20px; - padding-right: 20px; } - -/*# sourceMappingURL=style.css.map */ \ No newline at end of file diff --git a/site/resources/_gen/assets/scss/scss/style.scss_5ad6f408b0e3e473c748aac88af0ea18.json b/site/resources/_gen/assets/scss/scss/style.scss_5ad6f408b0e3e473c748aac88af0ea18.json deleted file mode 100644 index 28c014b0ad..0000000000 --- a/site/resources/_gen/assets/scss/scss/style.scss_5ad6f408b0e3e473c748aac88af0ea18.json +++ /dev/null @@ -1 +0,0 @@ -{"Target":"css/style.css","MediaType":"text/css","Data":{}} \ No newline at end of file diff --git a/site/static/css/tabs.css b/site/static/css/tabs.css new file mode 100644 index 0000000000..9bbc3ea8b0 --- /dev/null +++ b/site/static/css/tabs.css @@ -0,0 +1,56 @@ +/* Tabs CSS implementation. Borrowed from Skaffold & Kubernetes websites */ +ul.nav.nav-tabs { + padding: 0; + list-style-type: none; + overflow: hidden; + content: none; +} + +div.code-tabs li.nav-tab { + margin-top: 1.5rem; + padding: 10px 20px; + float: left; + text-align: center; + text-decoration: none; + color: #666; + font-size: 14px; + + border-top: 1px solid #CBCBCB; + border-left: 1px solid #CBCBCB; + border-right: 1px solid #CBCBCB; + margin-right: 0.5em; + + border-top-left-radius: 4px; + border-top-right-radius: 4px; + background-color: #E5E5E5; +} + +div.code-tabs li.active { + color:#000; + border-top: 1px solid #A9A9A9; + border-left: 1px solid #A9A9A9; + border-right: 1px solid #A9A9A9; + background: #f5f5f5; + font-weight: bold; +} + +div.code-tabs a.nav-tab { + all: unset; + cursor: pointer; +} + +div.tab-pane { + display: none; + margin-bottom: 3rem; +} + +div.tab-pane.active { + display: block; + padding: 2em; + background: #f5f5f5; + border: 1px solid #CBCBCB; +} + +div.code-tabs code { + word-break: keep-all; +} \ No newline at end of file diff --git a/site/static/js/tabs.js b/site/static/js/tabs.js new file mode 100644 index 0000000000..06ae6a5562 --- /dev/null +++ b/site/static/js/tabs.js @@ -0,0 +1,27 @@ +/* Tabs JS implementation. Borrowed from Skaffold */ +function initTabs() { + $('.tab-content').find('.tab-pane').each(function(idx, item) { + var navTabs = $(this).closest('.code-tabs').find('.nav-tabs'), + title = $(this).attr('title'); + navTabs.append(''); + }); + + $('.code-tabs ul.nav-tabs').each(function() { + $(this).find("li:first").addClass('active'); + }) + + $('.code-tabs .tab-content').each(function() { + $(this).find("div:first").addClass('active'); + }); + + $('.nav-tabs a').click(function(e){ + e.preventDefault(); + var tab = $(this).parent(), + tabIndex = tab.index(), + tabPanel = $(this).closest('.code-tabs'), + tabPane = tabPanel.find('.tab-pane').eq(tabIndex); + tabPanel.find('.active').removeClass('active'); + tab.addClass('active'); + tabPane.addClass('active'); + }); + } diff --git a/site/themes/docsy b/site/themes/docsy new file mode 160000 index 0000000000..493bb1a0af --- /dev/null +++ b/site/themes/docsy @@ -0,0 +1 @@ +Subproject commit 493bb1a0af92d1242f8396aeb1661dcd3a010db7 diff --git a/site/themes/hugo-whisper-theme b/site/themes/hugo-whisper-theme deleted file mode 160000 index c679e0b497..0000000000 --- a/site/themes/hugo-whisper-theme +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c679e0b497ad533a75fb4374d602cff91898b773 diff --git a/test.sh b/test.sh index 75d119acba..6f8d4705b8 100755 --- a/test.sh +++ b/test.sh @@ -20,36 +20,36 @@ exitcode=0 echo "= go mod ================================================================" go mod download 2>&1 | grep -v "go: finding" || true -go mod tidy -v && echo ok || ((exitcode+=2)) +go mod tidy -v && echo ok || ((exitcode += 2)) echo "= make lint =============================================================" -make -s lint && echo ok || ((exitcode+=4)) +make -s lint-ci && echo ok || ((exitcode += 4)) echo "= boilerplate ===========================================================" readonly PYTHON=$(type -P python || echo docker run --rm -it -v $(pwd):/minikube -w /minikube python python) readonly BDIR="./hack/boilerplate" -missing="$($PYTHON ${BDIR}/boilerplate.py --rootdir . --boilerplate-dir ${BDIR} | grep -v \/assets.go | grep -v \/translations.go || true)" +missing="$($PYTHON ${BDIR}/boilerplate.py --rootdir . --boilerplate-dir ${BDIR} | egrep -v '/assets.go|/translations.go|/site/themes/|/site/node_modules' || true)" if [[ -n "${missing}" ]]; then echo "boilerplate missing: $missing" echo "consider running: ${BDIR}/fix.sh" - ((exitcode+=4)) + ((exitcode += 4)) else echo "ok" fi echo "= schema_check ==========================================================" -go run deploy/minikube/schema_check.go >/dev/null && echo ok || ((exitcode+=8)) +go run deploy/minikube/schema_check.go >/dev/null && echo ok || ((exitcode += 8)) echo "= go test ===============================================================" cov_tmp="$(mktemp)" readonly COVERAGE_PATH=./out/coverage.txt -echo "mode: count" > "${COVERAGE_PATH}" +echo "mode: count" >"${COVERAGE_PATH}" pkgs=$(go list -f '{{ if .TestGoFiles }}{{.ImportPath}}{{end}}' ./cmd/... ./pkg/... | xargs) go test \ -tags "container_image_ostree_stub containers_image_openpgp" \ -covermode=count \ -coverprofile="${cov_tmp}" \ - ${pkgs} && echo ok || ((exitcode+=16)) -tail -n +2 "${cov_tmp}" >> "${COVERAGE_PATH}" + ${pkgs} && echo ok || ((exitcode += 16)) +tail -n +2 "${cov_tmp}" >>"${COVERAGE_PATH}" exit "${exitcode}" diff --git a/test/integration/a_download_only_test.go b/test/integration/a_download_only_test.go new file mode 100644 index 0000000000..dcd6e1cd45 --- /dev/null +++ b/test/integration/a_download_only_test.go @@ -0,0 +1,90 @@ +// +build integration + +/* +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. +*/ + +// a_download_only_test.go filename starts with a, for the purpose that it runs before all parallel tests and downloads the images and caches them. +package integration + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/hashicorp/go-getter" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/constants" + pkgutil "k8s.io/minikube/pkg/util" + "k8s.io/minikube/test/integration/util" +) + +// Note this test runs before all because filename is alphabetically first +// is used to cache images and binaries used by other parallel tests to avoid redownloading. +// TestDownloadOnly tests the --download-only option +func TestDownloadOnly(t *testing.T) { + p := profileName(t) + mk := NewMinikubeRunner(t, p) + if !isTestNoneDriver(t) { // none driver doesnt need to be deleted + defer mk.TearDown(t) + } + + t.Run("Oldest", func(t *testing.T) { + stdout, stderr, err := mk.Start("--download-only", fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion)) + if err != nil { + t.Errorf("%s minikube --download-only failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr) + } + }) + + t.Run("Newest", func(t *testing.T) { + stdout, stderr, err := mk.Start("--download-only", fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion)) + if err != nil { + t.Errorf("%s minikube --download-only failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr) + } + // TODO: add test to check if files are downloaded + }) + + t.Run("DownloadLatestRelease", func(t *testing.T) { + dest := filepath.Join(*testdataDir, fmt.Sprintf("minikube-%s-%s-latest-stable", runtime.GOOS, runtime.GOARCH)) + err := downloadMinikubeBinary(t, dest, "latest") + if err != nil { + t.Errorf("erorr downloading the latest minikube release %v", err) + } + }) +} + +// downloadMinikubeBinary downloads the minikube binary from github used by TestVersionUpgrade +// acts as a test setup for TestVersionUpgrade +func downloadMinikubeBinary(t *testing.T, dest string, version string) error { + t.Helper() + // Grab latest release binary + url := pkgutil.GetBinaryDownloadURL(version, runtime.GOOS) + download := func() error { + return getter.GetFile(dest, url) + } + + if err := util.RetryX(download, 13*time.Second, 5*time.Minute); err != nil { + return errors.Wrap(err, "Failed to get latest release binary") + } + if runtime.GOOS != "windows" { + if err := os.Chmod(dest, 0700); err != nil { + return err + } + } + return nil +} diff --git a/test/integration/addons_test.go b/test/integration/addons_test.go deleted file mode 100644 index 85b56a1c71..0000000000 --- a/test/integration/addons_test.go +++ /dev/null @@ -1,278 +0,0 @@ -// +build integration - -/* -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 integration - -import ( - "bufio" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "path" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/docker/machine/libmachine/state" - retryablehttp "github.com/hashicorp/go-retryablehttp" - "k8s.io/apimachinery/pkg/labels" - pkgutil "k8s.io/minikube/pkg/util" - "k8s.io/minikube/test/integration/util" -) - -func testAddons(t *testing.T) { - t.Parallel() - client, err := pkgutil.GetClient() - if err != nil { - t.Fatalf("Could not get kubernetes client: %v", err) - } - selector := labels.SelectorFromSet(labels.Set(map[string]string{"component": "kube-addon-manager"})) - if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { - t.Errorf("Error waiting for addon manager to be up") - } -} - -func readLineWithTimeout(b *bufio.Reader, timeout time.Duration) (string, error) { - s := make(chan string) - e := make(chan error) - go func() { - read, err := b.ReadString('\n') - if err != nil { - e <- err - } else { - s <- read - } - close(s) - close(e) - }() - - select { - case line := <-s: - return line, nil - case err := <-e: - return "", err - case <-time.After(timeout): - return "", fmt.Errorf("timeout after %s", timeout) - } -} - -func testDashboard(t *testing.T) { - t.Parallel() - minikubeRunner := NewMinikubeRunner(t) - cmd, out := minikubeRunner.RunDaemon("dashboard --url") - defer func() { - err := cmd.Process.Kill() - if err != nil { - t.Logf("Failed to kill dashboard command: %v", err) - } - }() - - s, err := readLineWithTimeout(out, 180*time.Second) - if err != nil { - t.Fatalf("failed to read url: %v", err) - } - - u, err := url.Parse(strings.TrimSpace(s)) - if err != nil { - t.Fatalf("failed to parse %q: %v", s, err) - } - - if u.Scheme != "http" { - t.Errorf("got Scheme %s, expected http", u.Scheme) - } - host, _, err := net.SplitHostPort(u.Host) - if err != nil { - t.Fatalf("failed SplitHostPort: %v", err) - } - if host != "127.0.0.1" { - t.Errorf("got host %s, expected 127.0.0.1", host) - } - - resp, err := retryablehttp.Get(u.String()) - if err != nil { - t.Fatalf("failed get: %v", err) - } - if resp.StatusCode != http.StatusOK { - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("Unable to read http response body: %v", err) - } - t.Errorf("%s returned status code %d, expected %d.\nbody:\n%s", u, resp.StatusCode, http.StatusOK, body) - } -} - -func testIngressController(t *testing.T) { - t.Parallel() - minikubeRunner := NewMinikubeRunner(t) - kubectlRunner := util.NewKubectlRunner(t) - - minikubeRunner.RunCommand("addons enable ingress", true) - if err := util.WaitForIngressControllerRunning(t); err != nil { - t.Fatalf("waiting for ingress-controller to be up: %v", err) - } - - if err := util.WaitForIngressDefaultBackendRunning(t); err != nil { - t.Fatalf("waiting for default-http-backend to be up: %v", err) - } - - curdir, err := filepath.Abs("") - if err != nil { - t.Errorf("Error getting the file path for current directory: %s", curdir) - } - ingressPath := path.Join(curdir, "testdata", "nginx-ing.yaml") - if _, err := kubectlRunner.RunCommand([]string{"create", "-f", ingressPath}); err != nil { - t.Fatalf("creating nginx ingress resource: %v", err) - } - - podPath := path.Join(curdir, "testdata", "nginx-pod-svc.yaml") - if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil { - t.Fatalf("creating nginx ingress resource: %v", err) - } - - if err := util.WaitForNginxRunning(t); err != nil { - t.Fatalf("waiting for nginx to be up: %v", err) - } - - checkIngress := func() error { - expectedStr := "Welcome to nginx!" - runCmd := fmt.Sprintf("curl http://127.0.0.1:80 -H 'Host: nginx.example.com'") - sshCmdOutput, _ := minikubeRunner.SSH(runCmd) - if !strings.Contains(sshCmdOutput, expectedStr) { - return fmt.Errorf("ExpectedStr sshCmdOutput to be: %s. Output was: %s", expectedStr, sshCmdOutput) - } - return nil - } - - if err := util.Retry(t, checkIngress, 3*time.Second, 5); err != nil { - t.Fatalf(err.Error()) - } - - defer func() { - for _, p := range []string{podPath, ingressPath} { - if out, err := kubectlRunner.RunCommand([]string{"delete", "-f", p}); err != nil { - t.Logf("delete -f %s failed: %v\noutput: %s\n", p, err, out) - } - } - }() - minikubeRunner.RunCommand("addons disable ingress", true) -} - -func testServicesList(t *testing.T) { - t.Parallel() - minikubeRunner := NewMinikubeRunner(t) - - checkServices := func() error { - output := minikubeRunner.RunCommand("service list", false) - if !strings.Contains(output, "kubernetes") { - return fmt.Errorf("Error, kubernetes service missing from output %s", output) - } - return nil - } - if err := util.Retry(t, checkServices, 2*time.Second, 5); err != nil { - t.Fatalf(err.Error()) - } -} - -func testGvisor(t *testing.T) { - minikubeRunner := NewMinikubeRunner(t) - minikubeRunner.RunCommand("addons enable gvisor", true) - - t.Log("waiting for gvisor controller to come up") - if err := util.WaitForGvisorControllerRunning(t); err != nil { - t.Fatalf("waiting for gvisor controller to be up: %v", err) - } - - createUntrustedWorkload(t) - - t.Log("making sure untrusted workload is Running") - if err := util.WaitForUntrustedNginxRunning(); err != nil { - t.Fatalf("waiting for nginx to be up: %v", err) - } - - t.Log("disabling gvisor addon") - minikubeRunner.RunCommand("addons disable gvisor", true) - t.Log("waiting for gvisor controller pod to be deleted") - if err := util.WaitForGvisorControllerDeleted(); err != nil { - t.Fatalf("waiting for gvisor controller to be deleted: %v", err) - } - - createUntrustedWorkload(t) - - t.Log("waiting for FailedCreatePodSandBox event") - if err := util.WaitForFailedCreatePodSandBoxEvent(); err != nil { - t.Fatalf("waiting for FailedCreatePodSandBox event: %v", err) - } - deleteUntrustedWorkload(t) -} - -func testGvisorRestart(t *testing.T) { - minikubeRunner := NewMinikubeRunner(t) - minikubeRunner.EnsureRunning() - minikubeRunner.RunCommand("addons enable gvisor", true) - - t.Log("waiting for gvisor controller to come up") - if err := util.WaitForGvisorControllerRunning(t); err != nil { - t.Fatalf("waiting for gvisor controller to be up: %v", err) - } - - // TODO: @priyawadhwa to add test for stop as well - minikubeRunner.RunCommand("delete", false) - minikubeRunner.CheckStatus(state.None.String()) - minikubeRunner.Start() - minikubeRunner.CheckStatus(state.Running.String()) - - t.Log("waiting for gvisor controller to come up") - if err := util.WaitForGvisorControllerRunning(t); err != nil { - t.Fatalf("waiting for gvisor controller to be up: %v", err) - } - - createUntrustedWorkload(t) - t.Log("making sure untrusted workload is Running") - if err := util.WaitForUntrustedNginxRunning(); err != nil { - t.Fatalf("waiting for nginx to be up: %v", err) - } - deleteUntrustedWorkload(t) -} - -func createUntrustedWorkload(t *testing.T) { - kubectlRunner := util.NewKubectlRunner(t) - curdir, err := filepath.Abs("") - if err != nil { - t.Errorf("Error getting the file path for current directory: %s", curdir) - } - untrustedPath := path.Join(curdir, "testdata", "nginx-untrusted.yaml") - t.Log("creating pod with untrusted workload annotation") - if _, err := kubectlRunner.RunCommand([]string{"replace", "-f", untrustedPath, "--force"}); err != nil { - t.Fatalf("creating untrusted nginx resource: %v", err) - } -} - -func deleteUntrustedWorkload(t *testing.T) { - kubectlRunner := util.NewKubectlRunner(t) - curdir, err := filepath.Abs("") - if err != nil { - t.Errorf("Error getting the file path for current directory: %s", curdir) - } - untrustedPath := path.Join(curdir, "testdata", "nginx-untrusted.yaml") - if _, err := kubectlRunner.RunCommand([]string{"delete", "-f", untrustedPath}); err != nil { - t.Logf("error deleting untrusted nginx resource: %v", err) - } -} diff --git a/test/integration/containerd_test.go b/test/integration/containerd_test.go new file mode 100644 index 0000000000..5d018bd8ac --- /dev/null +++ b/test/integration/containerd_test.go @@ -0,0 +1,133 @@ +// +build integration + +/* +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 integration + +import ( + "path/filepath" + "testing" + + "github.com/docker/machine/libmachine/state" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/labels" + commonutil "k8s.io/minikube/pkg/util" + "k8s.io/minikube/test/integration/util" +) + +func TestContainerd(t *testing.T) { + if isTestNoneDriver(t) { + t.Skip("Can't run containerd backend with none driver") + } + if shouldRunInParallel(t) { + t.Parallel() + } + + t.Run("GvisorRestart", testGvisorRestart) +} + +func testGvisorRestart(t *testing.T) { + p := profileName(t) + if shouldRunInParallel(t) { + t.Parallel() + } + mk := NewMinikubeRunner(t, p, "--wait=false") + defer mk.TearDown(t) + + stdout, stderr, err := mk.Start("--container-runtime=containerd", "--docker-opt containerd=/var/run/containerd/containerd.sock") + if err != nil { + t.Fatalf("failed to start minikube (for profile %s) failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr) + } + + mk.RunCommand("addons enable gvisor", true) + + t.Log("waiting for gvisor controller to come up") + if err := waitForGvisorControllerRunning(p); err != nil { + t.Errorf("waiting for gvisor controller to be up: %v", err) + } + + createUntrustedWorkload(t, p) + t.Log("making sure untrusted workload is Running") + if err := waitForUntrustedNginxRunning(p); err != nil { + t.Errorf("waiting for nginx to be up: %v", err) + } + deleteUntrustedWorkload(t, p) + + mk.RunCommand("delete", true) + stdout, stderr, err = mk.Start() + if err != nil { + t.Fatalf("failed to start minikube (for profile %s) failed : %v \nstdout: %s \nstderr: %s", t.Name(), err, stdout, stderr) + } + mk.CheckStatus(state.Running.String()) + + t.Log("waiting for gvisor controller to come up") + if err := waitForGvisorControllerRunning(p); err != nil { + t.Errorf("waiting for gvisor controller to be up: %v", err) + } + + createUntrustedWorkload(t, p) + t.Log("making sure untrusted workload is Running") + if err := waitForUntrustedNginxRunning(p); err != nil { + t.Errorf("waiting for nginx to be up: %v", err) + } + deleteUntrustedWorkload(t, p) +} + +func createUntrustedWorkload(t *testing.T, profile string) { + kr := util.NewKubectlRunner(t, profile) + untrustedPath := filepath.Join(*testdataDir, "nginx-untrusted.yaml") + t.Log("creating pod with untrusted workload annotation") + if _, err := kr.RunCommand([]string{"replace", "-f", untrustedPath, "--force"}); err != nil { + t.Fatalf("creating untrusted nginx resource: %v", err) + } +} + +func deleteUntrustedWorkload(t *testing.T, profile string) { + kr := util.NewKubectlRunner(t, profile) + untrustedPath := filepath.Join(*testdataDir, "nginx-untrusted.yaml") + if _, err := kr.RunCommand([]string{"delete", "-f", untrustedPath}); err != nil { + t.Logf("error deleting untrusted nginx resource: %v", err) + } +} + +// waitForGvisorControllerRunning waits for the gvisor controller pod to be running +func waitForGvisorControllerRunning(p string) error { + client, err := commonutil.GetClient(p) + if err != nil { + return errors.Wrap(err, "getting kubernetes client") + } + + selector := labels.SelectorFromSet(labels.Set(map[string]string{"kubernetes.io/minikube-addons": "gvisor"})) + if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { + return errors.Wrap(err, "waiting for gvisor controller pod to stabilize") + } + return nil +} + +// waitForUntrustedNginxRunning waits for the untrusted nginx pod to start running +func waitForUntrustedNginxRunning(miniProfile string) error { + client, err := commonutil.GetClient(miniProfile) + if err != nil { + return errors.Wrap(err, "getting kubernetes client") + } + + selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"})) + if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { + return errors.Wrap(err, "waiting for nginx pods") + } + return nil +} diff --git a/test/integration/docker_test.go b/test/integration/docker_test.go index b16e1ad9af..c7d02c36a3 100644 --- a/test/integration/docker_test.go +++ b/test/integration/docker_test.go @@ -20,34 +20,38 @@ package integration import ( "context" - "fmt" "strings" "testing" "time" + + "github.com/docker/machine/libmachine/state" ) func TestDocker(t *testing.T) { - mk := NewMinikubeRunner(t) - if strings.Contains(mk.StartArgs, "--vm-driver=none") { + if isTestNoneDriver(t) { t.Skip("skipping test as none driver does not bundle docker") } + p := profileName(t) + if shouldRunInParallel(t) { + t.Parallel() + } + mk := NewMinikubeRunner(t, p, "--wait=false") + defer mk.TearDown(t) // Start a timer for all remaining commands, to display failure output before a panic. - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) defer cancel() if _, _, err := mk.RunWithContext(ctx, "delete"); err != nil { t.Logf("pre-delete failed (probably ok): %v", err) } - startCmd := fmt.Sprintf("start %s %s %s", mk.StartArgs, mk.Args, - "--docker-env=FOO=BAR --docker-env=BAZ=BAT --docker-opt=debug --docker-opt=icc=true --alsologtostderr --v=5") - stdout, stderr, err := mk.RunWithContext(ctx, startCmd) + stdout, stderr, err := mk.Start("--docker-env=FOO=BAR", "--docker-env=BAZ=BAT", "--docker-opt=debug", " --docker-opt=icc=true") if err != nil { - t.Fatalf("start: %v\nstdout: %s\nstderr: %s", err, stdout, stderr) + t.Fatalf("TestDocker minikube start failed : %v\nstdout: %s\nstderr: %s", err, stdout, stderr) } - mk.EnsureRunning() + mk.CheckStatus(state.Running.String()) stdout, stderr, err = mk.RunWithContext(ctx, "ssh -- systemctl show docker --property=Environment --no-pager") if err != nil { diff --git a/test/integration/flags.go b/test/integration/flags.go index 5a5746ac7d..f8ad39211e 100644 --- a/test/integration/flags.go +++ b/test/integration/flags.go @@ -19,7 +19,9 @@ package integration import ( "flag" "os" + "strings" "testing" + "time" "k8s.io/minikube/test/integration/util" ) @@ -30,19 +32,56 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +var startTimeout = flag.Int("timeout", 25, "number of minutes to wait for minikube start") var binaryPath = flag.String("binary", "../../out/minikube", "path to minikube binary") -var args = flag.String("minikube-args", "", "Arguments to pass to minikube") +var globalArgs = flag.String("minikube-args", "", "Arguments to pass to minikube") var startArgs = flag.String("minikube-start-args", "", "Arguments to pass to minikube start") var mountArgs = flag.String("minikube-mount-args", "", "Arguments to pass to minikube mount") var testdataDir = flag.String("testdata-dir", "testdata", "the directory relative to test/integration where the testdata lives") +var parallel = flag.Bool("parallel", true, "run the tests in parallel, set false for run sequentially") // NewMinikubeRunner creates a new MinikubeRunner -func NewMinikubeRunner(t *testing.T) util.MinikubeRunner { +func NewMinikubeRunner(t *testing.T, profile string, extraStartArgs ...string) util.MinikubeRunner { return util.MinikubeRunner{ - Args: *args, - BinaryPath: *binaryPath, - StartArgs: *startArgs, - MountArgs: *mountArgs, - T: t, + Profile: profile, + BinaryPath: *binaryPath, + StartArgs: *startArgs + " " + strings.Join(extraStartArgs, " "), + GlobalArgs: *globalArgs, + MountArgs: *mountArgs, + TimeOutStart: time.Duration(*startTimeout) * time.Minute, + T: t, } } + +// isTestNoneDriver checks if the current test is for none driver +func isTestNoneDriver(t *testing.T) bool { + t.Helper() + return strings.Contains(*startArgs, "--vm-driver=none") +} + +// profileName chooses a profile name based on the test name +// to be used in minikube and kubecontext across that test +func profileName(t *testing.T) string { + t.Helper() + if isTestNoneDriver(t) { + return "minikube" + } + p := strings.Split(t.Name(), "/")[0] // for i.e, TestFunctional/SSH returns TestFunctional + if p == "TestFunctional" { + return "minikube" + } + return p +} + +// shouldRunInParallel deterimines if test should run in parallel or not +func shouldRunInParallel(t *testing.T) bool { + t.Helper() + if !*parallel { + return false + } + if isTestNoneDriver(t) { + return false + } + p := strings.Split(t.Name(), "/")[0] // for i.e, TestFunctional/SSH returns TestFunctional + return p != "TestFunctional" // gosimple lint: https://staticcheck.io/docs/checks#S1008 +} diff --git a/test/integration/fn_addons.go b/test/integration/fn_addons.go new file mode 100644 index 0000000000..70122964b3 --- /dev/null +++ b/test/integration/fn_addons.go @@ -0,0 +1,302 @@ +// +build integration + +/* +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 integration + +import ( + "bufio" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/pkg/errors" + + retryablehttp "github.com/hashicorp/go-retryablehttp" + "k8s.io/apimachinery/pkg/labels" + commonutil "k8s.io/minikube/pkg/util" + pkgutil "k8s.io/minikube/pkg/util" + "k8s.io/minikube/test/integration/util" +) + +func testAddons(t *testing.T) { + t.Parallel() + p := profileName(t) + client, err := pkgutil.GetClient(p) + if err != nil { + t.Fatalf("Could not get kubernetes client: %v", err) + } + selector := labels.SelectorFromSet(labels.Set(map[string]string{"component": "kube-addon-manager"})) + if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { + t.Errorf("Error waiting for addon manager to be up") + } +} + +func readLineWithTimeout(b *bufio.Reader, timeout time.Duration) (string, error) { + s := make(chan string) + e := make(chan error) + go func() { + read, err := b.ReadString('\n') + if err != nil { + e <- err + } else { + s <- read + } + close(s) + close(e) + }() + + select { + case line := <-s: + return line, nil + case err := <-e: + return "", err + case <-time.After(timeout): + return "", fmt.Errorf("timeout after %s", timeout) + } +} + +func testDashboard(t *testing.T) { + t.Parallel() + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") + cmd, out := mk.RunDaemon("dashboard --url") + defer func() { + err := cmd.Process.Kill() + if err != nil { + t.Logf("Failed to kill dashboard command: %v", err) + } + }() + + s, err := readLineWithTimeout(out, 240*time.Second) + if err != nil { + t.Fatalf("failed to read url: %v", err) + } + + u, err := url.Parse(strings.TrimSpace(s)) + if err != nil { + t.Fatalf("failed to parse %q: %v", s, err) + } + + if u.Scheme != "http" { + t.Errorf("got Scheme %s, expected http", u.Scheme) + } + host, _, err := net.SplitHostPort(u.Host) + if err != nil { + t.Fatalf("failed SplitHostPort: %v", err) + } + if host != "127.0.0.1" { + t.Errorf("got host %s, expected 127.0.0.1", host) + } + + resp, err := retryablehttp.Get(u.String()) + if err != nil { + t.Fatalf("failed get: %v", err) + } + if resp.StatusCode != http.StatusOK { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatalf("Unable to read http response body: %v", err) + } + t.Errorf("%s returned status code %d, expected %d.\nbody:\n%s", u, resp.StatusCode, http.StatusOK, body) + } +} + +func testIngressController(t *testing.T) { + t.Parallel() + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") + kr := util.NewKubectlRunner(t, p) + + mk.RunCommand("addons enable ingress", true) + if err := waitForIngressControllerRunning(p); err != nil { + t.Fatalf("Failed waiting for ingress-controller to be up: %v", err) + } + + ingressPath := filepath.Join(*testdataDir, "nginx-ing.yaml") + if _, err := kr.RunCommand([]string{"create", "-f", ingressPath}); err != nil { + t.Fatalf("Failed creating nginx ingress resource: %v", err) + } + + podPath := filepath.Join(*testdataDir, "nginx-pod-svc.yaml") + if _, err := kr.RunCommand([]string{"create", "-f", podPath}); err != nil { + t.Fatalf("Failed creating nginx ingress resource: %v", err) + } + + if err := waitForNginxRunning(t, p); err != nil { + t.Fatalf("Failed waiting for nginx to be up: %v", err) + } + + checkIngress := func() error { + expectedStr := "Welcome to nginx!" + runCmd := fmt.Sprintf("curl http://127.0.0.1:80 -H 'Host: nginx.example.com'") + sshCmdOutput, _ := mk.SSH(runCmd) + if !strings.Contains(sshCmdOutput, expectedStr) { + return fmt.Errorf("ExpectedStr sshCmdOutput to be: %s. Output was: %s", expectedStr, sshCmdOutput) + } + return nil + } + + if err := util.Retry(t, checkIngress, 2*time.Second, 5); err != nil { + t.Fatalf(err.Error()) + } + + defer func() { + for _, p := range []string{podPath, ingressPath} { + if out, err := kr.RunCommand([]string{"delete", "-f", p}); err != nil { + t.Logf("delete -f %s failed: %v\noutput: %s\n", p, err, out) + } + } + }() + mk.RunCommand("addons disable ingress", true) +} + +func testServicesList(t *testing.T) { + t.Parallel() + p := profileName(t) + mk := NewMinikubeRunner(t, p) + + checkServices := func() error { + output, stderr := mk.RunCommand("service list", false) + if !strings.Contains(output, "kubernetes") { + return fmt.Errorf("error, kubernetes service missing from output: %s, \n stderr: %s", output, stderr) + } + return nil + } + if err := util.Retry(t, checkServices, 2*time.Second, 5); err != nil { + t.Fatalf(err.Error()) + } +} +func testRegistry(t *testing.T) { + t.Parallel() + p := profileName(t) + mk := NewMinikubeRunner(t, p) + mk.RunCommand("addons enable registry", true) + client, err := pkgutil.GetClient(p) + if err != nil { + t.Fatalf("getting kubernetes client: %v", err) + } + if err := pkgutil.WaitForRCToStabilize(client, "kube-system", "registry", time.Minute*5); err != nil { + t.Fatalf("waiting for registry replicacontroller to stabilize: %v", err) + } + rs := labels.SelectorFromSet(labels.Set(map[string]string{"actual-registry": "true"})) + if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", rs); err != nil { + t.Fatalf("waiting for registry pods: %v", err) + } + ps, err := labels.Parse("kubernetes.io/minikube-addons=registry,actual-registry!=true") + if err != nil { + t.Fatalf("Unable to parse selector: %v", err) + } + if err := pkgutil.WaitForPodsWithLabelRunning(client, "kube-system", ps); err != nil { + t.Fatalf("waiting for registry-proxy pods: %v", err) + } + ip, stderr := mk.RunCommand("ip", true) + ip = strings.TrimSpace(ip) + endpoint := fmt.Sprintf("http://%s:%d", ip, 5000) + u, err := url.Parse(endpoint) + if err != nil { + t.Fatalf("failed to parse %q: %v stderr : %s", endpoint, err, stderr) + } + t.Log("checking registry access from outside cluster") + + // Check access from outside the cluster on port 5000, validing connectivity via registry-proxy + checkExternalAccess := func() error { + resp, err := retryablehttp.Get(u.String()) + if err != nil { + t.Errorf("failed get: %v", err) + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("%s returned status code %d, expected %d.\n", u, resp.StatusCode, http.StatusOK) + } + return nil + } + + if err := util.Retry(t, checkExternalAccess, 2*time.Second, 5); err != nil { + t.Fatalf(err.Error()) + } + + t.Log("checking registry access from inside cluster") + kr := util.NewKubectlRunner(t, p) + // TODO: Fix this + out, _ := kr.RunCommand([]string{ + "run", + "registry-test", + "--restart=Never", + "--image=busybox", + "-it", + "--", + "sh", + "-c", + "wget --spider -S 'http://registry.kube-system.svc.cluster.local' 2>&1 | grep 'HTTP/' | awk '{print $2}'"}) + internalCheckOutput := string(out) + expectedStr := "200" + if !strings.Contains(internalCheckOutput, expectedStr) { + t.Fatalf("ExpectedStr internalCheckOutput to be: %s. Output was: %s", expectedStr, internalCheckOutput) + } + + defer func() { + if _, err := kr.RunCommand([]string{"delete", "pod", "registry-test"}); err != nil { + t.Fatalf("failed to delete pod registry-test") + } + }() + mk.RunCommand("addons disable registry", true) +} + +// waitForNginxRunning waits for nginx service to be up +func waitForNginxRunning(t *testing.T, miniProfile string) error { + client, err := commonutil.GetClient(miniProfile) + + if err != nil { + return errors.Wrap(err, "getting kubernetes client") + } + + selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"})) + if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { + return errors.Wrap(err, "waiting for nginx pods") + } + + if err := commonutil.WaitForService(client, "default", "nginx", true, time.Millisecond*500, time.Minute*10); err != nil { + t.Errorf("Error waiting for nginx service to be up") + } + return nil +} + +// waitForIngressControllerRunning waits until ingress controller pod to be running +func waitForIngressControllerRunning(miniProfile string) error { + client, err := commonutil.GetClient(miniProfile) + if err != nil { + return errors.Wrap(err, "getting kubernetes client") + } + + if err := commonutil.WaitForDeploymentToStabilize(client, "kube-system", "nginx-ingress-controller", time.Minute*10); err != nil { + return errors.Wrap(err, "waiting for ingress-controller deployment to stabilize") + } + + selector := labels.SelectorFromSet(labels.Set(map[string]string{"app.kubernetes.io/name": "nginx-ingress-controller"})) + if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { + return errors.Wrap(err, "waiting for ingress-controller pods") + } + + return nil +} diff --git a/test/integration/cluster_dns_test.go b/test/integration/fn_cluster_dns.go similarity index 89% rename from test/integration/cluster_dns_test.go rename to test/integration/fn_cluster_dns.go index 229c009d3f..5206a32699 100644 --- a/test/integration/cluster_dns_test.go +++ b/test/integration/fn_cluster_dns.go @@ -32,13 +32,14 @@ import ( func testClusterDNS(t *testing.T) { t.Parallel() - client, err := pkgutil.GetClient() + p := profileName(t) + client, err := pkgutil.GetClient(p) if err != nil { t.Fatalf("Error getting kubernetes client %v", err) } - kr := util.NewKubectlRunner(t) - busybox := busyBoxPod(t, client, kr) + kr := util.NewKubectlRunner(t, p) + busybox := busyBoxPod(t, client, kr, p) defer func() { if _, err := kr.RunCommand([]string{"delete", "po", busybox}); err != nil { t.Errorf("delete failed: %v", err) @@ -61,12 +62,12 @@ func testClusterDNS(t *testing.T) { } } -func busyBoxPod(t *testing.T, c kubernetes.Interface, kr *util.KubectlRunner) string { +func busyBoxPod(t *testing.T, c kubernetes.Interface, kr *util.KubectlRunner, profile string) string { if _, err := kr.RunCommand([]string{"create", "-f", filepath.Join(*testdataDir, "busybox.yaml")}); err != nil { t.Fatalf("creating busybox pod: %s", err) } // TODO(tstromberg): Refactor WaitForBusyboxRunning to return name of pod. - if err := util.WaitForBusyboxRunning(t, "default"); err != nil { + if err := util.WaitForBusyboxRunning(t, "default", profile); err != nil { t.Fatalf("Waiting for busybox pod to be up: %v", err) } diff --git a/test/integration/cluster_env_test.go b/test/integration/fn_cluster_env.go similarity index 86% rename from test/integration/cluster_env_test.go rename to test/integration/fn_cluster_env.go index 132ece7d4a..671c00b19a 100644 --- a/test/integration/cluster_env_test.go +++ b/test/integration/fn_cluster_env.go @@ -30,14 +30,14 @@ import ( // Assert that docker-env subcommand outputs usable information for "docker ps" func testClusterEnv(t *testing.T) { t.Parallel() - - r := NewMinikubeRunner(t) + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") // Set a specific shell syntax so that we don't have to handle every possible user shell - envOut := r.RunCommand("docker-env --shell=bash", true) - vars := r.ParseEnvCmdOutput(envOut) + envOut, stderr := mk.RunCommand("docker-env --shell=bash", true) + vars := mk.ParseEnvCmdOutput(envOut) if len(vars) == 0 { - t.Fatalf("Failed to parse env vars:\n%s", envOut) + t.Fatalf("Failed to parse env vars:\n%s, \n stderr: %s ", envOut, stderr) } for k, v := range vars { t.Logf("Found: %s=%s", k, v) diff --git a/test/integration/cluster_logs_test.go b/test/integration/fn_cluster_logs.go similarity index 89% rename from test/integration/cluster_logs_test.go rename to test/integration/fn_cluster_logs.go index e5675fa2f4..c97912a916 100644 --- a/test/integration/cluster_logs_test.go +++ b/test/integration/fn_cluster_logs.go @@ -25,9 +25,9 @@ import ( func testClusterLogs(t *testing.T) { t.Parallel() - minikubeRunner := NewMinikubeRunner(t) - minikubeRunner.EnsureRunning() - logsCmdOutput := minikubeRunner.GetLogs() + p := profileName(t) + mk := NewMinikubeRunner(t, p) + logsCmdOutput := mk.GetLogs() // check for # of lines or check for strings logWords := []string{"minikube", ".go"} diff --git a/test/integration/cluster_ssh_test.go b/test/integration/fn_cluster_ssh.go similarity index 76% rename from test/integration/cluster_ssh_test.go rename to test/integration/fn_cluster_ssh.go index 5c57f67276..cb2744ae96 100644 --- a/test/integration/cluster_ssh_test.go +++ b/test/integration/fn_cluster_ssh.go @@ -25,10 +25,11 @@ import ( func testClusterSSH(t *testing.T) { t.Parallel() - minikubeRunner := NewMinikubeRunner(t) + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") expectedStr := "hello" - sshCmdOutput := minikubeRunner.RunCommand("ssh echo "+expectedStr, true) + sshCmdOutput, stderr := mk.RunCommand("ssh echo "+expectedStr, true) if !strings.Contains(sshCmdOutput, expectedStr) { - t.Fatalf("ExpectedStr sshCmdOutput to be: %s. Output was: %s", expectedStr, sshCmdOutput) + t.Fatalf("ExpectedStr sshCmdOutput to be: %s. Output was: %s Stderr: %s", expectedStr, sshCmdOutput, stderr) } } diff --git a/test/integration/cluster_status_test.go b/test/integration/fn_cluster_status.go similarity index 87% rename from test/integration/cluster_status_test.go rename to test/integration/fn_cluster_status.go index 9af4dd98a8..06128d0684 100644 --- a/test/integration/cluster_status_test.go +++ b/test/integration/fn_cluster_status.go @@ -28,12 +28,13 @@ import ( ) func testClusterStatus(t *testing.T) { - kubectlRunner := util.NewKubectlRunner(t) + p := profileName(t) + kr := util.NewKubectlRunner(t, p) cs := api.ComponentStatusList{} healthy := func() error { t.Log("Checking if cluster is healthy.") - if err := kubectlRunner.RunCommandParseOutput([]string{"get", "cs"}, &cs); err != nil { + if err := kr.RunCommandParseOutput([]string{"get", "cs"}, &cs); err != nil { return err } for _, i := range cs.Items { @@ -45,7 +46,7 @@ func testClusterStatus(t *testing.T) { status = c.Status } if status != api.ConditionTrue { - err := fmt.Errorf("Component %s is not Healthy! Status: %s", i.GetName(), status) + err := fmt.Errorf("component %s is not Healthy! Status: %s", i.GetName(), status) t.Logf("Retrying, %v", err) return err } diff --git a/test/integration/mount_test.go b/test/integration/fn_mount.go similarity index 71% rename from test/integration/mount_test.go rename to test/integration/fn_mount.go index a55d04e417..8459d8d6f8 100644 --- a/test/integration/mount_test.go +++ b/test/integration/fn_mount.go @@ -22,7 +22,6 @@ import ( "fmt" "io/ioutil" "os" - "path" "path/filepath" "runtime" "strings" @@ -38,12 +37,13 @@ func testMounting(t *testing.T) { if runtime.GOOS == "darwin" { t.Skip("mount tests disabled in darwin due to timeout (issue#3200)") } - if strings.Contains(*args, "--vm-driver=none") { + if isTestNoneDriver(t) { t.Skip("skipping test for none driver as it does not need mount") } t.Parallel() - minikubeRunner := NewMinikubeRunner(t) + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") tempDir, err := ioutil.TempDir("", "mounttest") if err != nil { @@ -51,8 +51,8 @@ func testMounting(t *testing.T) { } defer os.RemoveAll(tempDir) - mountCmd := getMountCmd(minikubeRunner, tempDir) - cmd, _, _ := minikubeRunner.RunDaemon2(mountCmd) + mountCmd := getMountCmd(mk, tempDir) + cmd, _, _ := mk.RunDaemon2(mountCmd) defer func() { err := cmd.Process.Kill() if err != nil { @@ -60,14 +60,9 @@ func testMounting(t *testing.T) { } }() - kubectlRunner := util.NewKubectlRunner(t) + kr := util.NewKubectlRunner(t, p) podName := "busybox-mount" - curdir, err := filepath.Abs("") - if err != nil { - t.Errorf("Error getting the file path for current directory: %s", curdir) - } - podPath := path.Join(curdir, "testdata", "busybox-mount-test.yaml") - + podPath := filepath.Join(*testdataDir, "busybox-mount-test.yaml") // Write file in mounted dir from host expected := "test\n" if err := writeFilesFromHost(tempDir, []string{"fromhost", "fromhostremove"}, expected); err != nil { @@ -77,14 +72,14 @@ func testMounting(t *testing.T) { // Create the pods we need outside the main test loop. setupTest := func() error { t.Logf("Deploying pod from: %s", podPath) - if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil { + if _, err := kr.RunCommand([]string{"create", "-f", podPath}); err != nil { return err } return nil } defer func() { t.Logf("Deleting pod from: %s", podPath) - if out, err := kubectlRunner.RunCommand([]string{"delete", "-f", podPath}); err != nil { + if out, err := kr.RunCommand([]string{"delete", "-f", podPath}); err != nil { t.Logf("delete -f %s failed: %v\noutput: %s\n", podPath, err, out) } }() @@ -93,13 +88,13 @@ func testMounting(t *testing.T) { t.Fatal("mountTest failed with error:", err) } - if err := waitForPods(map[string]string{"integration-test": "busybox-mount"}); err != nil { + if err := waitForPods(map[string]string{"integration-test": "busybox-mount"}, p); err != nil { t.Fatalf("Error waiting for busybox mount pod to be up: %v", err) } t.Logf("Pods appear to be running") mountTest := func() error { - if err := verifyFiles(minikubeRunner, kubectlRunner, tempDir, podName, expected); err != nil { + if err := verifyFiles(mk, kr, tempDir, podName, expected); err != nil { t.Fatalf(err.Error()) } @@ -111,10 +106,10 @@ func testMounting(t *testing.T) { } -func getMountCmd(minikubeRunner util.MinikubeRunner, mountDir string) string { +func getMountCmd(mk util.MinikubeRunner, mountDir string) string { var mountCmd string - if len(minikubeRunner.MountArgs) > 0 { - mountCmd = fmt.Sprintf("mount %s %s:/mount-9p", minikubeRunner.MountArgs, mountDir) + if len(mk.MountArgs) > 0 { + mountCmd = fmt.Sprintf("mount %s %s:/mount-9p", mk.MountArgs, mountDir) } else { mountCmd = fmt.Sprintf("mount %s:/mount-9p", mountDir) } @@ -126,14 +121,14 @@ func writeFilesFromHost(mountedDir string, files []string, content string) error path := filepath.Join(mountedDir, file) err := ioutil.WriteFile(path, []byte(content), 0644) if err != nil { - return fmt.Errorf("Unexpected error while writing file %s: %v", path, err) + return fmt.Errorf("unexpected error while writing file %s: %v", path, err) } } return nil } -func waitForPods(s map[string]string) error { - client, err := pkgutil.GetClient() +func waitForPods(s map[string]string, profile string) error { + client, err := pkgutil.GetClient(profile) if err != nil { return fmt.Errorf("getting kubernetes client: %v", err) } @@ -144,7 +139,7 @@ func waitForPods(s map[string]string) error { return nil } -func verifyFiles(minikubeRunner util.MinikubeRunner, kubectlRunner *util.KubectlRunner, tempDir string, podName string, expected string) error { +func verifyFiles(mk util.MinikubeRunner, kr *util.KubectlRunner, tempDir string, podName string, expected string) error { path := filepath.Join(tempDir, "frompod") out, err := ioutil.ReadFile(path) if err != nil { @@ -156,7 +151,7 @@ func verifyFiles(minikubeRunner util.MinikubeRunner, kubectlRunner *util.Kubectl } // test that file written from host was read in by the pod via cat /mount-9p/fromhost; - if out, err = kubectlRunner.RunCommand([]string{"logs", podName}); err != nil { + if out, err = kr.RunCommand([]string{"logs", podName}); err != nil { return err } if string(out) != expected { @@ -167,32 +162,32 @@ func verifyFiles(minikubeRunner util.MinikubeRunner, kubectlRunner *util.Kubectl files := []string{"fromhost", "frompod"} for _, file := range files { statCmd := fmt.Sprintf("stat /mount-9p/%s", file) - statOutput, err := minikubeRunner.SSH(statCmd) + statOutput, err := mk.SSH(statCmd) if err != nil { - return fmt.Errorf("Unable to stat %s via SSH. error %v, %s", file, err, statOutput) + return fmt.Errorf("inable to stat %s via SSH. error %v, %s", file, err, statOutput) } if runtime.GOOS == "windows" { if strings.Contains(statOutput, "Access: 1970-01-01") { - return fmt.Errorf("Invalid access time\n%s", statOutput) + return fmt.Errorf("invalid access time\n%s", statOutput) } } if strings.Contains(statOutput, "Modify: 1970-01-01") { - return fmt.Errorf("Invalid modify time\n%s", statOutput) + return fmt.Errorf("invalid modify time\n%s", statOutput) } } // test that fromhostremove was deleted by the pod from the mount via rm /mount-9p/fromhostremove path = filepath.Join(tempDir, "fromhostremove") if _, err := os.Stat(path); err == nil { - return fmt.Errorf("Expected file %s to be removed", path) + return fmt.Errorf("expected file %s to be removed", path) } // test that frompodremove can be deleted on the host path = filepath.Join(tempDir, "frompodremove") if err := os.Remove(path); err != nil { - return fmt.Errorf("Unexpected error removing file %s: %v", path, err) + return fmt.Errorf("unexpected error removing file %s: %v", path, err) } return nil diff --git a/test/integration/fn_profile.go b/test/integration/fn_profile.go new file mode 100644 index 0000000000..9160a21190 --- /dev/null +++ b/test/integration/fn_profile.go @@ -0,0 +1,35 @@ +// +build integration + +/* +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 integration + +import ( + "strings" + "testing" +) + +// testProfileList tests the `minikube profile list` command +func testProfileList(t *testing.T) { + p := profileName(t) + t.Parallel() + mk := NewMinikubeRunner(t, p, "--wait=false") + out, stderr := mk.RunCommand("profile list", true) + if !strings.Contains(out, p) { + t.Errorf("Error , failed to read profile name (%s) in `profile list` command output : \n %q : \n stderr: %s ", p, out, stderr) + } +} diff --git a/test/integration/pv_test.go b/test/integration/fn_pv.go similarity index 82% rename from test/integration/pv_test.go rename to test/integration/fn_pv.go index f648f79db7..e83c38ce32 100644 --- a/test/integration/pv_test.go +++ b/test/integration/fn_pv.go @@ -39,11 +39,13 @@ var ( ) func testProvisioning(t *testing.T) { + p := profileName(t) t.Parallel() - kubectlRunner := util.NewKubectlRunner(t) + + kr := util.NewKubectlRunner(t, p) defer func() { - if out, err := kubectlRunner.RunCommand([]string{"delete", "pvc", pvcName}); err != nil { + if out, err := kr.RunCommand([]string{"delete", "pvc", pvcName}); err != nil { t.Logf("delete pvc %s failed: %v\noutput: %s\n", pvcName, err, out) } }() @@ -53,7 +55,7 @@ func testProvisioning(t *testing.T) { checkStorageClass := func() error { scl := storage.StorageClassList{} - if err := kubectlRunner.RunCommandParseOutput([]string{"get", "storageclass"}, &scl); err != nil { + if err := kr.RunCommandParseOutput([]string{"get", "storageclass"}, &scl); err != nil { return fmt.Errorf("get storageclass: %v", err) } @@ -63,14 +65,14 @@ func testProvisioning(t *testing.T) { return fmt.Errorf("no default StorageClass yet") } - if err := util.Retry(t, checkStorageClass, 5*time.Second, 20); err != nil { + if err := util.Retry(t, checkStorageClass, 10*time.Second, 10); err != nil { t.Fatalf("no default storage class after retry: %v", err) } // Check that the storage provisioner pod is running checkPodRunning := func() error { - client, err := commonutil.GetClient() + client, err := commonutil.GetClient(p) if err != nil { return errors.Wrap(err, "getting kubernetes client") } @@ -82,20 +84,20 @@ func testProvisioning(t *testing.T) { return nil } - if err := checkPodRunning(); err != nil { + if err := util.Retry(t, checkPodRunning, 2*time.Second, 5); err != nil { t.Fatalf("Check storage-provisioner pod running failed with error: %v", err) } // Now create the PVC pvcPath := filepath.Join(*testdataDir, "pvc.yaml") - if _, err := kubectlRunner.RunCommand([]string{"create", "-f", pvcPath}); err != nil { + if _, err := kr.RunCommand([]string{"create", "-f", pvcPath}); err != nil { t.Fatalf("Error creating pvc: %v", err) } // And check that it gets bound to a PV. checkStorage := func() error { pvc := core.PersistentVolumeClaim{} - if err := kubectlRunner.RunCommandParseOutput(pvcCmd, &pvc); err != nil { + if err := kr.RunCommandParseOutput(pvcCmd, &pvc); err != nil { return err } // The test passes if the volume claim gets bound. diff --git a/test/integration/tunnel_test.go b/test/integration/fn_tunnel.go similarity index 81% rename from test/integration/tunnel_test.go rename to test/integration/fn_tunnel.go index c50f4fc04a..79e1b3af5b 100644 --- a/test/integration/tunnel_test.go +++ b/test/integration/fn_tunnel.go @@ -21,7 +21,6 @@ import ( "io/ioutil" "net/http" "os/exec" - "path" "path/filepath" "runtime" "strings" @@ -46,11 +45,13 @@ func testTunnel(t *testing.T) { } t.Log("starting tunnel test...") - runner := NewMinikubeRunner(t) + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") go func() { - output := runner.RunCommand("tunnel --alsologtostderr -v 8 --logtostderr", true) + output, stderr := mk.RunCommand("tunnel --alsologtostderr -v 8 --logtostderr", true) if t.Failed() { - fmt.Println(output) + t.Errorf("tunnel stderr : %s", stderr) + t.Errorf("tunnel output : %s", output) } }() @@ -60,19 +61,15 @@ func testTunnel(t *testing.T) { t.Fatal(errors.Wrap(err, "cleaning up tunnels")) } - kubectlRunner := util.NewKubectlRunner(t) + kr := util.NewKubectlRunner(t, p) t.Log("deploying nginx...") - curdir, err := filepath.Abs("") - if err != nil { - t.Errorf("Error getting the file path for current directory: %s", curdir) - } - podPath := path.Join(curdir, "testdata", "testsvc.yaml") - if _, err := kubectlRunner.RunCommand([]string{"apply", "-f", podPath}); err != nil { + podPath := filepath.Join(*testdataDir, "testsvc.yaml") + if _, err := kr.RunCommand([]string{"apply", "-f", podPath}); err != nil { t.Fatalf("creating nginx ingress resource: %s", err) } - client, err := commonutil.GetClient() + client, err := commonutil.GetClient(p) if err != nil { t.Fatal(errors.Wrap(err, "getting kubernetes client")) @@ -89,13 +86,13 @@ func testTunnel(t *testing.T) { t.Log("getting nginx ingress...") - nginxIP, err := getIngress(kubectlRunner) + nginxIP, err := getIngress(kr) if err != nil { t.Errorf("error getting ingress IP for nginx: %s", err) } if len(nginxIP) == 0 { - stdout, err := describeIngress(kubectlRunner) + stdout, err := describeIngress(kr) if err != nil { t.Errorf("error debugging nginx service: %s", err) @@ -113,12 +110,12 @@ func testTunnel(t *testing.T) { } } -func getIngress(kubectlRunner *util.KubectlRunner) (string, error) { +func getIngress(kr *util.KubectlRunner) (string, error) { nginxIP := "" var ret error err := wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) { cmd := []string{"get", "svc", "nginx-svc", "-o", "jsonpath={.status.loadBalancer.ingress[0].ip}"} - stdout, err := kubectlRunner.RunCommand(cmd) + stdout, err := kr.RunCommand(cmd) switch { case err == nil: nginxIP = string(stdout) @@ -137,8 +134,8 @@ func getIngress(kubectlRunner *util.KubectlRunner) (string, error) { return nginxIP, ret } -func describeIngress(kubectlRunner *util.KubectlRunner) ([]byte, error) { - return kubectlRunner.RunCommand([]string{"get", "svc", "nginx-svc", "-o", "jsonpath={.status}"}) +func describeIngress(kr *util.KubectlRunner) ([]byte, error) { + return kr.RunCommand([]string{"get", "svc", "nginx-svc", "-o", "jsonpath={.status}"}) } // getResponseBody returns the contents of a URL diff --git a/test/integration/functional_test.go b/test/integration/functional_test.go index d5c9374b3c..e44a720cc9 100644 --- a/test/integration/functional_test.go +++ b/test/integration/functional_test.go @@ -19,62 +19,48 @@ limitations under the License. package integration import ( +<<<<<<< HEAD "os" "strings" +======= +>>>>>>> 45e5265c3570cf9c7b3cedda09f58ab8e6edbdfe "testing" - - "github.com/docker/machine/libmachine/state" - "k8s.io/minikube/test/integration/util" ) func TestFunctional(t *testing.T) { - r := NewMinikubeRunner(t) - r.EnsureRunning() - // This one is not parallel, and ensures the cluster comes up - // before we run any other tests. - t.Run("Status", testClusterStatus) - - t.Run("DNS", testClusterDNS) - t.Run("Logs", testClusterLogs) - t.Run("Addons", testAddons) - t.Run("Dashboard", testDashboard) - t.Run("ServicesList", testServicesList) - t.Run("Provisioning", testProvisioning) - t.Run("Tunnel", testTunnel) - - if !usingNoneDriver(r) { - t.Run("EnvVars", testClusterEnv) - t.Run("SSH", testClusterSSH) - t.Run("IngressController", testIngressController) - t.Run("Mounting", testMounting) + p := profileName(t) + mk := NewMinikubeRunner(t, p) + stdout, stderr, err := mk.Start() + if err != nil { + t.Fatalf("failed to start minikube failed : %v\nstdout: %s\nstderr: %s", err, stdout, stderr) } -} - -func TestFunctionalContainerd(t *testing.T) { - r := NewMinikubeRunner(t) - - if usingNoneDriver(r) { - t.Skip("Can't run containerd backend with none driver") + if !isTestNoneDriver(t) { // none driver doesn't need to be deleted + defer mk.TearDown(t) } - if r.GetStatus() != state.None.String() { - r.RunCommand("delete", true) - } + // group is needed to make sure tear down runs after parallel runs + // https://github.com/golang/go/issues/17791#issuecomment-258476786 + t.Run("group", func(t *testing.T) { + // This one is not parallel, and ensures the cluster comes up + // before we run any other tests. + t.Run("Status", testClusterStatus) + t.Run("ProfileList", testProfileList) + t.Run("DNS", testClusterDNS) + t.Run("Logs", testClusterLogs) + t.Run("Addons", testAddons) + t.Run("Registry", testRegistry) + t.Run("Dashboard", testDashboard) + t.Run("ServicesList", testServicesList) + t.Run("Provisioning", testProvisioning) + t.Run("Tunnel", testTunnel) - t.Log("starting minikube, $MINIKUBE_HOME=", os.Getenv("MINIKUBE_HOME")) + if !isTestNoneDriver(t) { + t.Run("EnvVars", testClusterEnv) + t.Run("SSH", testClusterSSH) + t.Run("IngressController", testIngressController) + t.Run("Mounting", testMounting) + } - output := r.RunCommand("cache list", true) - t.Log("Cache list:", string(output)) + }) - r.Start("--container-runtime=containerd", "--docker-opt containerd=/var/run/containerd/containerd.sock") - r.RunCommand("cache add gcr.io/k8s-minikube/gvisor-addon:latest", true) - - t.Run("Gvisor", testGvisor) - t.Run("GvisorRestart", testGvisorRestart) - r.RunCommand("delete", true) -} - -// usingNoneDriver returns true if using the none driver -func usingNoneDriver(r util.MinikubeRunner) bool { - return strings.Contains(r.StartArgs, "--vm-driver=none") } diff --git a/test/integration/iso_test.go b/test/integration/iso_test.go index 4a7806abf8..94092e1b5a 100644 --- a/test/integration/iso_test.go +++ b/test/integration/iso_test.go @@ -25,26 +25,37 @@ import ( ) func TestISO(t *testing.T) { + p := profileName(t) + if shouldRunInParallel(t) { + t.Parallel() + } - minikubeRunner := NewMinikubeRunner(t) - - minikubeRunner.RunCommand("delete", false) - minikubeRunner.Start() + mk := NewMinikubeRunner(t, p, "--wait=false") + mk.RunCommand("delete", false) + stdout, stderr, err := mk.Start() + if err != nil { + t.Fatalf("failed to start minikube (for profile %s) %s) failed : %v\nstdout: %s\nstderr: %s", t.Name(), err, stdout, stderr) + } + if !isTestNoneDriver(t) { // none driver doesn't need to be deleted + defer mk.TearDown(t) + } t.Run("permissions", testMountPermissions) t.Run("packages", testPackages) t.Run("persistence", testPersistence) + } func testMountPermissions(t *testing.T) { - minikubeRunner := NewMinikubeRunner(t) + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") // test mount permissions mountPoints := []string{"/Users", "/hosthome"} perms := "drwxr-xr-x" foundMount := false for _, dir := range mountPoints { - output, err := minikubeRunner.SSH(fmt.Sprintf("ls -l %s", dir)) + output, err := mk.SSH(fmt.Sprintf("ls -l %s", dir)) if err != nil { continue } @@ -59,7 +70,8 @@ func testMountPermissions(t *testing.T) { } func testPackages(t *testing.T) { - minikubeRunner := NewMinikubeRunner(t) + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") packages := []string{ "git", @@ -73,7 +85,7 @@ func testPackages(t *testing.T) { } for _, pkg := range packages { - if output, err := minikubeRunner.SSH(fmt.Sprintf("which %s", pkg)); err != nil { + if output, err := mk.SSH(fmt.Sprintf("which %s", pkg)); err != nil { t.Errorf("Error finding package: %s. Error: %v. Output: %s", pkg, err, output) } } @@ -81,7 +93,8 @@ func testPackages(t *testing.T) { } func testPersistence(t *testing.T) { - minikubeRunner := NewMinikubeRunner(t) + p := profileName(t) + mk := NewMinikubeRunner(t, p, "--wait=false") for _, dir := range []string{ "/data", @@ -92,7 +105,7 @@ func testPersistence(t *testing.T) { "/var/lib/toolbox", "/var/lib/boot2docker", } { - output, err := minikubeRunner.SSH(fmt.Sprintf("df %s | tail -n 1 | awk '{print $1}'", dir)) + output, err := mk.SSH(fmt.Sprintf("df %s | tail -n 1 | awk '{print $1}'", dir)) if err != nil { t.Errorf("Error checking device for %s. Error: %v", dir, err) } diff --git a/test/integration/persistence_test.go b/test/integration/persistence_test.go index 158c70668d..c88e1b6cbf 100644 --- a/test/integration/persistence_test.go +++ b/test/integration/persistence_test.go @@ -19,60 +19,51 @@ limitations under the License. package integration import ( - "path" "path/filepath" - "strings" "testing" - "time" "github.com/docker/machine/libmachine/state" "k8s.io/minikube/test/integration/util" ) func TestPersistence(t *testing.T) { - minikubeRunner := NewMinikubeRunner(t) - if strings.Contains(minikubeRunner.StartArgs, "--vm-driver=none") { + if isTestNoneDriver(t) { t.Skip("skipping test as none driver does not support persistence") } - minikubeRunner.EnsureRunning() + p := profileName(t) + if shouldRunInParallel(t) { + t.Parallel() + } - kubectlRunner := util.NewKubectlRunner(t) - curdir, err := filepath.Abs("") + mk := NewMinikubeRunner(t, p, "--wait=false") + defer mk.TearDown(t) + + stdout, stderr, err := mk.Start() if err != nil { - t.Errorf("Error getting the file path for current directory: %s", curdir) + t.Fatalf("failed to start minikube (for profile %s) failed : %v\nstdout: %s\nstderr: %s", t.Name(), err, stdout, stderr) } - podPath := path.Join(curdir, "testdata", "busybox.yaml") - - // Create a pod and wait for it to be running. - if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil { - t.Fatalf("Error creating test pod: %v", err) + kr := util.NewKubectlRunner(t, p) + if _, err := kr.RunCommand([]string{"create", "-f", filepath.Join(*testdataDir, "busybox.yaml")}); err != nil { + t.Fatalf("creating busybox pod: %s", err) } - - verify := func(t *testing.T) { - if err := util.WaitForBusyboxRunning(t, "default"); err != nil { + verifyBusybox := func(t *testing.T) { + if err := util.WaitForBusyboxRunning(t, "default", p); err != nil { t.Fatalf("waiting for busybox to be up: %v", err) } } - // Make sure everything is up before we stop. - verify(t) + verifyBusybox(t) - // Now restart minikube and make sure the pod is still there. - // minikubeRunner.RunCommand("stop", true) - // minikubeRunner.CheckStatus("Stopped") - checkStop := func() error { - minikubeRunner.RunCommand("stop", true) - return minikubeRunner.CheckStatusNoFail(state.Stopped.String()) + mk.RunCommand("stop", true) + mk.CheckStatus(state.Stopped.String()) + + stdout, stderr, err = mk.Start() + if err != nil { + t.Fatalf("failed to start minikube (for profile %s) failed : %v\nstdout: %s\nstderr: %s", t.Name(), err, stdout, stderr) } - - if err := util.Retry(t, checkStop, 5*time.Second, 6); err != nil { - t.Fatalf("timed out while checking stopped status: %v", err) - } - - minikubeRunner.Start() - minikubeRunner.CheckStatus(state.Running.String()) + mk.CheckStatus(state.Running.String()) // Make sure the same things come up after we've restarted. - verify(t) + verifyBusybox(t) } diff --git a/test/integration/start_stop_delete_test.go b/test/integration/start_stop_delete_test.go index 5810919359..2d13a17069 100644 --- a/test/integration/start_stop_delete_test.go +++ b/test/integration/start_stop_delete_test.go @@ -31,86 +31,96 @@ import ( ) func TestStartStop(t *testing.T) { - tests := []struct { - name string - args []string - }{ - {"nocache_oldest", []string{ - "--cache-images=false", - fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion), - // default is the network created by libvirt, if we change the name minikube won't boot - // because the given network doesn't exist - "--kvm-network=default", - "--kvm-qemu-uri=qemu:///system", - }}, - {"feature_gates_newest_cni", []string{ - "--feature-gates", - "ServerSideApply=true", - "--network-plugin=cni", - "--extra-config=kubelet.network-plugin=cni", - "--extra-config=kubeadm.pod-network-cidr=192.168.111.111/16", - fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion), - }}, - {"containerd_and_non_default_apiserver_port", []string{ - "--container-runtime=containerd", - "--docker-opt containerd=/var/run/containerd/containerd.sock", - "--apiserver-port=8444", - }}, - {"crio_ignore_preflights", []string{ - "--container-runtime=crio", - "--extra-config", - "kubeadm.ignore-preflight-errors=SystemVerification", - }}, + p := profileName(t) // gets profile name used for minikube and kube context + if shouldRunInParallel(t) { + t.Parallel() } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - r := NewMinikubeRunner(t) - if !strings.Contains(test.name, "docker") && usingNoneDriver(r) { - t.Skipf("skipping %s - incompatible with none driver", test.name) - } + t.Run("group", func(t *testing.T) { + if shouldRunInParallel(t) { + t.Parallel() + } + tests := []struct { + name string + args []string + }{ + {"oldest", []string{ // nocache_oldest + "--cache-images=false", + fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion), + // default is the network created by libvirt, if we change the name minikube won't boot + // because the given network doesn't exist + "--kvm-network=default", + "--kvm-qemu-uri=qemu:///system", + }}, + {"cni", []string{ // feature_gates_newest_cni + "--feature-gates", + "ServerSideApply=true", + "--network-plugin=cni", + "--extra-config=kubelet.network-plugin=cni", + "--extra-config=kubeadm.pod-network-cidr=192.168.111.111/16", + fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion), + }}, + {"containerd", []string{ // containerd_and_non_default_apiserver_port + "--container-runtime=containerd", + "--docker-opt containerd=/var/run/containerd/containerd.sock", + "--apiserver-port=8444", + }}, + {"crio", []string{ // crio_ignore_preflights + "--container-runtime=crio", + "--extra-config", + "kubeadm.ignore-preflight-errors=SystemVerification", + }}, + } - r.RunCommand("config set WantReportErrorPrompt false", true) - r.RunCommand("delete", false) - r.CheckStatus(state.None.String()) - r.Start(test.args...) - r.CheckStatus(state.Running.String()) + for _, tc := range tests { + n := tc.name // because similar to https://golang.org/doc/faq#closures_and_goroutines + t.Run(tc.name, func(t *testing.T) { + if shouldRunInParallel(t) { + t.Parallel() + } - ip := r.RunCommand("ip", true) - ip = strings.TrimRight(ip, "\n") - if net.ParseIP(ip) == nil { - t.Fatalf("IP command returned an invalid address: %s", ip) - } + pn := p + n // TestStartStopoldest + mk := NewMinikubeRunner(t, pn, "--wait=false") + // TODO : redundant first clause ? never happens? + if !strings.Contains(pn, "docker") && isTestNoneDriver(t) { + t.Skipf("skipping %s - incompatible with none driver", t.Name()) + } - // check for the current-context before and after the stop - kubectlRunner := util.NewKubectlRunner(t) - currentContext, err := kubectlRunner.RunCommand([]string{"config", "current-context"}) - if err != nil { - t.Fatalf("Failed to fetch current-context") - } - if strings.TrimRight(string(currentContext), "\n") != "minikube" { - t.Fatalf("got current-context - %q, want current-context %q", string(currentContext), "minikube") - } + mk.RunCommand("config set WantReportErrorPrompt false", true) + stdout, stderr, err := mk.Start(tc.args...) + if err != nil { + t.Fatalf("failed to start minikube (for profile %s) failed : %v\nstdout: %s\nstderr: %s", pn, err, stdout, stderr) + } - checkStop := func() error { - r.RunCommand("stop", true) - return r.CheckStatusNoFail(state.Stopped.String()) - } + mk.CheckStatus(state.Running.String()) - if err := util.Retry(t, checkStop, 5*time.Second, 6); err != nil { - t.Fatalf("timed out while checking stopped status: %v", err) - } + ip, stderr := mk.RunCommand("ip", true) + ip = strings.TrimRight(ip, "\n") + if net.ParseIP(ip) == nil { + t.Fatalf("IP command returned an invalid address: %s \n %s", ip, stderr) + } - // running this command results in error when the current-context is not set - if err := r.Run("config current-context"); err != nil { - t.Logf("current-context is not set to minikube") - } + stop := func() error { + stdout, stderr, err = mk.RunCommandRetriable("stop") + return mk.CheckStatusNoFail(state.Stopped.String()) + } - r.Start(test.args...) - r.CheckStatus(state.Running.String()) + err = util.RetryX(stop, 10*time.Second, 2*time.Minute) + mk.CheckStatus(state.Stopped.String()) - r.RunCommand("delete", true) - r.CheckStatus(state.None.String()) - }) - } + // TODO medyagh: + // https://github.com/kubernetes/minikube/issues/4854 + + stdout, stderr, err = mk.Start(tc.args...) + if err != nil { + t.Fatalf("failed to start minikube (for profile %s) failed : %v\nstdout: %s\nstderr: %s", t.Name(), err, stdout, stderr) + } + + mk.CheckStatus(state.Running.String()) + + mk.RunCommand("delete", true) + mk.CheckStatus(state.None.String()) + }) + } + }) } diff --git a/test/integration/util/common.go b/test/integration/util/common.go new file mode 100644 index 0000000000..34c6a9e078 --- /dev/null +++ b/test/integration/util/common.go @@ -0,0 +1,82 @@ +/* +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 util + +import ( + "fmt" + "testing" + "time" + + "github.com/cenkalti/backoff" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/labels" + commonutil "k8s.io/minikube/pkg/util" +) + +// WaitForBusyboxRunning waits until busybox pod to be running +func WaitForBusyboxRunning(t *testing.T, namespace string, miniProfile string) error { + client, err := commonutil.GetClient(miniProfile) + if err != nil { + return errors.Wrap(err, "getting kubernetes client") + } + selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox"})) + return commonutil.WaitForPodsWithLabelRunning(client, namespace, selector) +} + +// Retry tries the callback for a number of attempts, with a delay between attempts +func Retry(t *testing.T, callback func() error, d time.Duration, attempts int) (err error) { + for i := 0; i < attempts; i++ { + err = callback() + if err == nil { + return nil + } + time.Sleep(d) + } + return err +} + +// Retry2 tries the callback for a number of attempts, with a delay without *testing.T +func Retry2(callback func() error, d time.Duration, attempts int) (err error) { + for i := 0; i < attempts; i++ { + err = callback() + if err == nil { + return nil + } + time.Sleep(d) + } + return err +} + +// RetryX is expontential backoff retry +func RetryX(callback func() error, initInterv time.Duration, maxTime time.Duration) error { + b := backoff.NewExponentialBackOff() + b.MaxElapsedTime = maxTime + b.InitialInterval = initInterv + b.RandomizationFactor = 0.5 + b.Multiplier = 1.5 + b.Reset() + return backoff.Retry(callback, b) +} + +// Logf writes logs to stdout if -v is set. +func Logf(str string, args ...interface{}) { + if !testing.Verbose() { + return + } + fmt.Printf(" %s | ", time.Now().Format("15:04:05")) + fmt.Println(fmt.Sprintf(str, args...)) +} diff --git a/test/integration/util/kubectl_runner.go b/test/integration/util/kubectl_runner.go new file mode 100644 index 0000000000..1f33fb20f3 --- /dev/null +++ b/test/integration/util/kubectl_runner.go @@ -0,0 +1,117 @@ +/* +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 util + +import ( + "bytes" + "encoding/json" + "fmt" + "math/rand" + "os/exec" + "testing" + "time" + + commonutil "k8s.io/minikube/pkg/util" +) + +const kubectlBinary = "kubectl" + +// KubectlRunner runs a command using kubectl +type KubectlRunner struct { + Profile string // kube-context maps to a minikube profile + T *testing.T + BinaryPath string +} + +// NewKubectlRunner creates a new KubectlRunner +func NewKubectlRunner(t *testing.T, profile ...string) *KubectlRunner { + if profile == nil { + profile = []string{"minikube"} + } + + p, err := exec.LookPath(kubectlBinary) + if err != nil { + t.Fatalf("Couldn't find kubectl on path.") + } + return &KubectlRunner{Profile: profile[0], BinaryPath: p, T: t} +} + +// RunCommandParseOutput runs a command and parses the JSON output +func (k *KubectlRunner) RunCommandParseOutput(args []string, outputObj interface{}, useKubeContext ...bool) error { + args = append(args, "-o=json") + output, err := k.RunCommand(args, useKubeContext...) + if err != nil { + return err + } + d := json.NewDecoder(bytes.NewReader(output)) + if err := d.Decode(outputObj); err != nil { + return err + } + return nil +} + +// RunCommand runs a command, returning stdout +func (k *KubectlRunner) RunCommand(args []string, useKubeContext ...bool) (stdout []byte, err error) { + + if useKubeContext == nil { + useKubeContext = []bool{true} + } + if useKubeContext[0] { + kubecContextArg := fmt.Sprintf("--context=%s", k.Profile) + args = append([]string{kubecContextArg}, args...) // prepending --context so it can be with with -- space + } + + inner := func() error { + cmd := exec.Command(k.BinaryPath, args...) + stdout, err = cmd.CombinedOutput() + if err != nil { + retriable := &commonutil.RetriableError{Err: fmt.Errorf("error running command %s: %v. Stdout: \n %s", args, err, stdout)} + k.T.Log(retriable) + return retriable + } + return nil + } + + err = commonutil.RetryAfter(3, inner, 2*time.Second) + return stdout, err +} + +// CreateRandomNamespace creates a random namespace +func (k *KubectlRunner) CreateRandomNamespace() string { + const strLen = 20 + name := genRandString(strLen) + if _, err := k.RunCommand([]string{"create", "namespace", name}); err != nil { + k.T.Fatalf("Error creating namespace: %v", err) + } + return name +} + +func genRandString(strLen int) string { + const chars = "abcdefghijklmnopqrstuvwxyz0123456789" + rand.Seed(time.Now().UTC().UnixNano()) + result := make([]byte, strLen) + for i := 0; i < strLen; i++ { + result[i] = chars[rand.Intn(len(chars))] + } + return string(result) +} + +// DeleteNamespace deletes the namespace +func (k *KubectlRunner) DeleteNamespace(namespace string) error { + _, err := k.RunCommand([]string{"delete", "namespace", namespace}) + return err +} diff --git a/test/integration/util/minikube_runner.go b/test/integration/util/minikube_runner.go new file mode 100644 index 0000000000..5e38c09651 --- /dev/null +++ b/test/integration/util/minikube_runner.go @@ -0,0 +1,318 @@ +/* +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 ( + "bufio" + "bytes" + "context" + "fmt" + "os/exec" + "path/filepath" + "regexp" + "strings" + "sync" + "testing" + "time" + + "github.com/docker/machine/libmachine/state" + "github.com/pkg/errors" + "k8s.io/minikube/pkg/minikube/assets" + commonutil "k8s.io/minikube/pkg/util" +) + +// MinikubeRunner runs a command +type MinikubeRunner struct { + Profile string + T *testing.T + BinaryPath string + GlobalArgs string + StartArgs string + MountArgs string + Runtime string + TimeOutStart time.Duration // time to wait for minikube start before killing it +} + +// Remove removes a file +func (m *MinikubeRunner) Remove(f assets.CopyableFile) error { + _, err := m.SSH(fmt.Sprintf("rm -rf %s", filepath.Join(f.GetTargetDir(), f.GetTargetName()))) + return err +} + +// teeRun runs a command, streaming stdout, stderr to console +func (m *MinikubeRunner) teeRun(cmd *exec.Cmd, waitForRun ...bool) (string, string, error) { + w := true + if waitForRun != nil { + w = waitForRun[0] + } + + errPipe, err := cmd.StderrPipe() + if err != nil { + return "", "", err + } + outPipe, err := cmd.StdoutPipe() + if err != nil { + return "", "", err + } + + if err := cmd.Start(); err != nil { + return "", "", err + } + if w { + var outB bytes.Buffer + var errB bytes.Buffer + var wg sync.WaitGroup + wg.Add(2) + go func() { + if err := commonutil.TeePrefix(commonutil.ErrPrefix, errPipe, &errB, Logf); err != nil { + m.T.Logf("tee: %v", err) + } + wg.Done() + }() + go func() { + if err := commonutil.TeePrefix(commonutil.OutPrefix, outPipe, &outB, Logf); err != nil { + m.T.Logf("tee: %v", err) + } + wg.Done() + }() + err = cmd.Wait() + wg.Wait() + return outB.String(), errB.String(), err + + } + return "", "", err +} + +// RunCommand executes a command, optionally checking for error and by default waits for run to finish +func (m *MinikubeRunner) RunCommand(cmdStr string, failError bool, waitForRun ...bool) (string, string) { + profileArg := fmt.Sprintf("-p=%s ", m.Profile) + cmdStr = profileArg + cmdStr + cmdArgs := strings.Split(cmdStr, " ") + path, _ := filepath.Abs(m.BinaryPath) + + cmd := exec.Command(path, cmdArgs...) + Logf("Run: %s", cmd.Args) + stdout, stderr, err := m.teeRun(cmd, waitForRun...) + if err != nil { + errMsg := "" + if exitError, ok := err.(*exec.ExitError); ok { + errMsg = fmt.Sprintf("Error running command: %s %s. Output: %s Stderr: %s", cmdStr, exitError.Stderr, stdout, stderr) + } else { + errMsg = fmt.Sprintf("Error running command: %s %s. Output: %s", cmdStr, stderr, stdout) + } + if failError { + m.T.Fatalf(errMsg) + } else { + m.T.Errorf(errMsg) + } + } + return stdout, stderr +} + +// RunCommandRetriable Error executes a command, returns error +// the purpose of this command is to make it retriable and +// better logging for retrying +func (m *MinikubeRunner) RunCommandRetriable(cmdStr string, waitForRun ...bool) (stdout string, stderr string, err error) { + profileArg := fmt.Sprintf("-p=%s ", m.Profile) + cmdStr = profileArg + cmdStr + cmdArgs := strings.Split(cmdStr, " ") + path, _ := filepath.Abs(m.BinaryPath) + + cmd := exec.Command(path, cmdArgs...) + Logf("Run: %s", cmd.Args) + stdout, stderr, err = m.teeRun(cmd, waitForRun...) + if err != nil { + if exitError, ok := err.(*exec.ExitError); ok { + m.T.Logf("temporary error: running command: %s %s. Output: \n%s", cmdStr, exitError.Stderr, stdout) + } else { + m.T.Logf("temporary error: running command: %s %s. Output: \n%s", cmdStr, stderr, stdout) + } + } + return stdout, stderr, err +} + +// RunWithContext calls the minikube command with a context, useful for timeouts. +func (m *MinikubeRunner) RunWithContext(ctx context.Context, cmdStr string, wait ...bool) (string, string, error) { + profileArg := fmt.Sprintf("-p=%s ", m.Profile) + cmdStr = profileArg + cmdStr + cmdArgs := strings.Split(cmdStr, " ") + path, _ := filepath.Abs(m.BinaryPath) + + cmd := exec.CommandContext(ctx, path, cmdArgs...) + Logf("Run: %s", cmd.Args) + return m.teeRun(cmd, wait...) +} + +// RunDaemon executes a command, returning the stdout +func (m *MinikubeRunner) RunDaemon(cmdStr string) (*exec.Cmd, *bufio.Reader) { + profileArg := fmt.Sprintf("-p=%s ", m.Profile) + cmdStr = profileArg + cmdStr + cmdArgs := strings.Split(cmdStr, " ") + path, _ := filepath.Abs(m.BinaryPath) + + cmd := exec.Command(path, cmdArgs...) + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + m.T.Fatalf("stdout pipe failed: %s %v", cmdStr, err) + } + stderrPipe, err := cmd.StderrPipe() + if err != nil { + m.T.Fatalf("stderr pipe failed: %s %v", cmdStr, err) + } + + var errB bytes.Buffer + go func() { + if err := commonutil.TeePrefix(commonutil.ErrPrefix, stderrPipe, &errB, Logf); err != nil { + m.T.Logf("tee: %v", err) + } + }() + + err = cmd.Start() + if err != nil { + m.T.Fatalf("Error running command: %s %v", cmdStr, err) + } + return cmd, bufio.NewReader(stdoutPipe) + +} + +// RunDaemon2 executes a command, returning the stdout and stderr +func (m *MinikubeRunner) RunDaemon2(cmdStr string) (*exec.Cmd, *bufio.Reader, *bufio.Reader) { + profileArg := fmt.Sprintf("-p=%s ", m.Profile) + cmdStr = profileArg + cmdStr + cmdArgs := strings.Split(cmdStr, " ") + path, _ := filepath.Abs(m.BinaryPath) + cmd := exec.Command(path, cmdArgs...) + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + m.T.Fatalf("stdout pipe failed: %s %v", cmdStr, err) + } + stderrPipe, err := cmd.StderrPipe() + if err != nil { + m.T.Fatalf("stderr pipe failed: %s %v", cmdStr, err) + } + + err = cmd.Start() + if err != nil { + m.T.Fatalf("Error running command: %s %v", cmdStr, err) + } + return cmd, bufio.NewReader(stdoutPipe), bufio.NewReader(stderrPipe) +} + +// SSH returns the output of running a command using SSH +func (m *MinikubeRunner) SSH(cmdStr string) (string, error) { + profileArg := fmt.Sprintf("-p=%s", m.Profile) + path, _ := filepath.Abs(m.BinaryPath) + + cmd := exec.Command(path, profileArg, "ssh", cmdStr) + Logf("SSH: %s", cmdStr) + stdout, err := cmd.CombinedOutput() + Logf("Output: %s", stdout) + if err, ok := err.(*exec.ExitError); ok { + return string(stdout), err + } + return string(stdout), nil +} + +// Start starts the cluster +func (m *MinikubeRunner) Start(opts ...string) (stdout string, stderr string, err error) { + cmd := fmt.Sprintf("start %s %s %s", m.StartArgs, m.GlobalArgs, strings.Join(opts, " ")) + s := func() error { + stdout, stderr, err = m.RunCommandRetriable(cmd) + return err + } + err = RetryX(s, 10*time.Second, m.TimeOutStart) + return stdout, stderr, err +} + +// TearDown deletes minikube without waiting for it. used to free up ram/cpu after each test +func (m *MinikubeRunner) TearDown(t *testing.T) { + profileArg := fmt.Sprintf("-p=%s", m.Profile) + path, _ := filepath.Abs(m.BinaryPath) + cmd := exec.Command(path, profileArg, "delete") + err := cmd.Start() + if err != nil { + t.Errorf("error tearing down minikube %s : %v", profileArg, err) + } +} + +// EnsureRunning makes sure the container runtime is running +func (m *MinikubeRunner) EnsureRunning(opts ...string) { + s, _, err := m.Status() + if err != nil { + m.T.Errorf("error getting status for ensure running: %v", err) + } + if s != state.Running.String() { + stdout, stderr, err := m.Start(opts...) + if err != nil { + m.T.Errorf("error starting while running EnsureRunning : %v , stdout %s stderr %s", err, stdout, stderr) + } + } + m.CheckStatus(state.Running.String()) +} + +// ParseEnvCmdOutput parses the output of `env` (assumes bash) +func (m *MinikubeRunner) ParseEnvCmdOutput(out string) map[string]string { + env := map[string]string{} + re := regexp.MustCompile(`(\w+?) ?= ?"?(.+?)"?\n`) + for _, m := range re.FindAllStringSubmatch(out, -1) { + env[m[1]] = m[2] + } + return env +} + +// Status returns the status of a service +func (m *MinikubeRunner) Status() (status string, stderr string, err error) { + cmd := fmt.Sprintf("status --format={{.Host}} %s", m.GlobalArgs) + s := func() error { + status, stderr, err = m.RunCommandRetriable(cmd) + status = strings.TrimRight(status, "\n") + return err + } + err = RetryX(s, 15*time.Second, 1*time.Minute) + if err != nil && (status == state.None.String() || status == state.Stopped.String()) { + err = nil // because https://github.com/kubernetes/minikube/issues/4932 + } + return status, stderr, err +} + +// GetLogs returns the logs of a service +func (m *MinikubeRunner) GetLogs() string { + // TODO: this test needs to check sterr too ! + stdout, _ := m.RunCommand(fmt.Sprintf("logs %s", m.GlobalArgs), true) + return stdout +} + +// CheckStatus makes sure the service has the desired status, or cause fatal error +func (m *MinikubeRunner) CheckStatus(desired string) { + err := m.CheckStatusNoFail(desired) + if err != nil { // none status returns 1 exit code + m.T.Fatalf("%v", err) + } +} + +// CheckStatusNoFail makes sure the service has the desired status, returning error +func (m *MinikubeRunner) CheckStatusNoFail(desired string) error { + s, stderr, err := m.Status() + if s != desired { + return fmt.Errorf("got state: %q, expected %q : stderr: %s err: %v ", s, desired, stderr, err) + } + + if err != nil { + return errors.Wrapf(err, stderr) + } + return nil +} diff --git a/test/integration/util/util.go b/test/integration/util/util.go deleted file mode 100644 index 08e1cebb27..0000000000 --- a/test/integration/util/util.go +++ /dev/null @@ -1,467 +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 ( - "bufio" - "bytes" - "context" - "encoding/json" - "fmt" - "math/rand" - "os/exec" - "path/filepath" - "regexp" - "strings" - "sync" - "testing" - "time" - - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/minikube/pkg/minikube/assets" - commonutil "k8s.io/minikube/pkg/util" -) - -const kubectlBinary = "kubectl" - -// MinikubeRunner runs a command -type MinikubeRunner struct { - T *testing.T - BinaryPath string - Args string - StartArgs string - MountArgs string - Runtime string -} - -// Logf writes logs to stdout if -v is set. -func Logf(str string, args ...interface{}) { - if !testing.Verbose() { - return - } - fmt.Printf(" %s | ", time.Now().Format("15:04:05")) - fmt.Println(fmt.Sprintf(str, args...)) -} - -// Run executes a command -func (m *MinikubeRunner) Run(cmd string) error { - _, err := m.SSH(cmd) - return err -} - -// Copy copies a file -func (m *MinikubeRunner) Copy(f assets.CopyableFile) error { - path, _ := filepath.Abs(m.BinaryPath) - cmd := exec.Command("/bin/bash", "-c", path, "ssh", "--", fmt.Sprintf("cat >> %s", filepath.Join(f.GetTargetDir(), f.GetTargetName()))) - Logf("Running: %s", cmd.Args) - return cmd.Run() -} - -// CombinedOutput executes a command, returning the combined stdout and stderr -func (m *MinikubeRunner) CombinedOutput(cmd string) (string, error) { - return m.SSH(cmd) -} - -// Remove removes a file -func (m *MinikubeRunner) Remove(f assets.CopyableFile) error { - _, err := m.SSH(fmt.Sprintf("rm -rf %s", filepath.Join(f.GetTargetDir(), f.GetTargetName()))) - return err -} - -// teeRun runs a command, streaming stdout, stderr to console -func (m *MinikubeRunner) teeRun(cmd *exec.Cmd) (string, string, error) { - errPipe, err := cmd.StderrPipe() - if err != nil { - return "", "", err - } - outPipe, err := cmd.StdoutPipe() - if err != nil { - return "", "", err - } - - if err := cmd.Start(); err != nil { - return "", "", err - } - var outB bytes.Buffer - var errB bytes.Buffer - var wg sync.WaitGroup - wg.Add(2) - go func() { - if err := commonutil.TeePrefix(commonutil.ErrPrefix, errPipe, &errB, Logf); err != nil { - m.T.Logf("tee: %v", err) - } - wg.Done() - }() - go func() { - if err := commonutil.TeePrefix(commonutil.OutPrefix, outPipe, &outB, Logf); err != nil { - m.T.Logf("tee: %v", err) - } - wg.Done() - }() - err = cmd.Wait() - wg.Wait() - return outB.String(), errB.String(), err -} - -// RunCommand executes a command, optionally checking for error -func (m *MinikubeRunner) RunCommand(command string, checkError bool) string { - commandArr := strings.Split(command, " ") - path, _ := filepath.Abs(m.BinaryPath) - cmd := exec.Command(path, commandArr...) - Logf("Run: %s", cmd.Args) - stdout, stderr, err := m.teeRun(cmd) - if checkError && err != nil { - if exitError, ok := err.(*exec.ExitError); ok { - m.T.Fatalf("Error running command: %s %s. Output: %s", command, exitError.Stderr, stdout) - } else { - m.T.Fatalf("Error running command: %s %v. Output: %s", command, err, stderr) - } - } - return stdout -} - -// RunWithContext calls the minikube command with a context, useful for timeouts. -func (m *MinikubeRunner) RunWithContext(ctx context.Context, command string) (string, string, error) { - commandArr := strings.Split(command, " ") - path, _ := filepath.Abs(m.BinaryPath) - cmd := exec.CommandContext(ctx, path, commandArr...) - Logf("Run: %s", cmd.Args) - return m.teeRun(cmd) -} - -// RunDaemon executes a command, returning the stdout -func (m *MinikubeRunner) RunDaemon(command string) (*exec.Cmd, *bufio.Reader) { - commandArr := strings.Split(command, " ") - path, _ := filepath.Abs(m.BinaryPath) - cmd := exec.Command(path, commandArr...) - stdoutPipe, err := cmd.StdoutPipe() - if err != nil { - m.T.Fatalf("stdout pipe failed: %s %v", command, err) - } - stderrPipe, err := cmd.StderrPipe() - if err != nil { - m.T.Fatalf("stderr pipe failed: %s %v", command, err) - } - - var errB bytes.Buffer - go func() { - if err := commonutil.TeePrefix(commonutil.ErrPrefix, stderrPipe, &errB, Logf); err != nil { - m.T.Logf("tee: %v", err) - } - }() - - err = cmd.Start() - if err != nil { - m.T.Fatalf("Error running command: %s %v", command, err) - } - return cmd, bufio.NewReader(stdoutPipe) - -} - -// RunDaemon2 executes a command, returning the stdout and stderr -func (m *MinikubeRunner) RunDaemon2(command string) (*exec.Cmd, *bufio.Reader, *bufio.Reader) { - commandArr := strings.Split(command, " ") - path, _ := filepath.Abs(m.BinaryPath) - cmd := exec.Command(path, commandArr...) - stdoutPipe, err := cmd.StdoutPipe() - if err != nil { - m.T.Fatalf("stdout pipe failed: %s %v", command, err) - } - stderrPipe, err := cmd.StderrPipe() - if err != nil { - m.T.Fatalf("stderr pipe failed: %s %v", command, err) - } - - err = cmd.Start() - if err != nil { - m.T.Fatalf("Error running command: %s %v", command, err) - } - return cmd, bufio.NewReader(stdoutPipe), bufio.NewReader(stderrPipe) -} - -// SSH returns the output of running a command using SSH -func (m *MinikubeRunner) SSH(command string) (string, error) { - path, _ := filepath.Abs(m.BinaryPath) - cmd := exec.Command(path, "ssh", command) - Logf("SSH: %s", command) - - stdout, err := cmd.CombinedOutput() - Logf("Output: %s", stdout) - if err, ok := err.(*exec.ExitError); ok { - return string(stdout), err - } - return string(stdout), nil -} - -// Start starts the container runtime -func (m *MinikubeRunner) Start(opts ...string) { - cmd := fmt.Sprintf("start %s %s %s --alsologtostderr --v=2", m.StartArgs, m.Args, strings.Join(opts, " ")) - m.RunCommand(cmd, true) -} - -// EnsureRunning makes sure the container runtime is running -func (m *MinikubeRunner) EnsureRunning() { - if m.GetStatus() != "Running" { - m.Start() - } - m.CheckStatus("Running") -} - -// ParseEnvCmdOutput parses the output of `env` (assumes bash) -func (m *MinikubeRunner) ParseEnvCmdOutput(out string) map[string]string { - env := map[string]string{} - re := regexp.MustCompile(`(\w+?) ?= ?"?(.+?)"?\n`) - for _, m := range re.FindAllStringSubmatch(out, -1) { - env[m[1]] = m[2] - } - return env -} - -// GetStatus returns the status of a service -func (m *MinikubeRunner) GetStatus() string { - return m.RunCommand(fmt.Sprintf("status --format={{.Host}} %s", m.Args), false) -} - -// GetLogs returns the logs of a service -func (m *MinikubeRunner) GetLogs() string { - return m.RunCommand(fmt.Sprintf("logs %s", m.Args), true) -} - -// CheckStatus makes sure the service has the desired status, or cause fatal error -func (m *MinikubeRunner) CheckStatus(desired string) { - if err := m.CheckStatusNoFail(desired); err != nil { - m.T.Fatalf("%v", err) - } -} - -// CheckStatusNoFail makes sure the service has the desired status, returning error -func (m *MinikubeRunner) CheckStatusNoFail(desired string) error { - s := m.GetStatus() - if s != desired { - return fmt.Errorf("got state: %q, expected %q", s, desired) - } - return nil -} - -// KubectlRunner runs a command using kubectl -type KubectlRunner struct { - T *testing.T - BinaryPath string -} - -// NewKubectlRunner creates a new KubectlRunner -func NewKubectlRunner(t *testing.T) *KubectlRunner { - p, err := exec.LookPath(kubectlBinary) - if err != nil { - t.Fatalf("Couldn't find kubectl on path.") - } - return &KubectlRunner{BinaryPath: p, T: t} -} - -// RunCommandParseOutput runs a command and parses the JSON output -func (k *KubectlRunner) RunCommandParseOutput(args []string, outputObj interface{}) error { - args = append(args, "-o=json") - output, err := k.RunCommand(args) - if err != nil { - return err - } - d := json.NewDecoder(bytes.NewReader(output)) - if err := d.Decode(outputObj); err != nil { - return err - } - return nil -} - -// RunCommand runs a command, returning stdout -func (k *KubectlRunner) RunCommand(args []string) (stdout []byte, err error) { - inner := func() error { - cmd := exec.Command(k.BinaryPath, args...) - stdout, err = cmd.CombinedOutput() - if err != nil { - retriable := &commonutil.RetriableError{Err: fmt.Errorf("error running command %s: %v. Stdout: \n %s", args, err, stdout)} - k.T.Log(retriable) - return retriable - } - return nil - } - - err = commonutil.RetryAfter(3, inner, 2*time.Second) - return stdout, err -} - -// CreateRandomNamespace creates a random namespace -func (k *KubectlRunner) CreateRandomNamespace() string { - const strLen = 20 - name := genRandString(strLen) - if _, err := k.RunCommand([]string{"create", "namespace", name}); err != nil { - k.T.Fatalf("Error creating namespace: %v", err) - } - return name -} - -func genRandString(strLen int) string { - const chars = "abcdefghijklmnopqrstuvwxyz0123456789" - rand.Seed(time.Now().UTC().UnixNano()) - result := make([]byte, strLen) - for i := 0; i < strLen; i++ { - result[i] = chars[rand.Intn(len(chars))] - } - return string(result) -} - -// DeleteNamespace deletes the namespace -func (k *KubectlRunner) DeleteNamespace(namespace string) error { - _, err := k.RunCommand([]string{"delete", "namespace", namespace}) - return err -} - -// WaitForBusyboxRunning waits until busybox pod to be running -func WaitForBusyboxRunning(t *testing.T, namespace string) error { - client, err := commonutil.GetClient() - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox"})) - return commonutil.WaitForPodsWithLabelRunning(client, namespace, selector) -} - -// WaitForIngressControllerRunning waits until ingress controller pod to be running -func WaitForIngressControllerRunning(t *testing.T) error { - client, err := commonutil.GetClient() - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - - if err := commonutil.WaitForDeploymentToStabilize(client, "kube-system", "nginx-ingress-controller", time.Minute*10); err != nil { - return errors.Wrap(err, "waiting for ingress-controller deployment to stabilize") - } - - selector := labels.SelectorFromSet(labels.Set(map[string]string{"app.kubernetes.io/name": "nginx-ingress-controller"})) - if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { - return errors.Wrap(err, "waiting for ingress-controller pods") - } - - return nil -} - -// WaitForIngressDefaultBackendRunning waits until ingress default backend pod to be running -func WaitForIngressDefaultBackendRunning(t *testing.T) error { - client, err := commonutil.GetClient() - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - - if err := commonutil.WaitForDeploymentToStabilize(client, "kube-system", "default-http-backend", time.Minute*10); err != nil { - return errors.Wrap(err, "waiting for default-http-backend deployment to stabilize") - } - - if err := commonutil.WaitForService(client, "kube-system", "default-http-backend", true, time.Millisecond*500, time.Minute*10); err != nil { - return errors.Wrap(err, "waiting for default-http-backend service to be up") - } - - if err := commonutil.WaitForServiceEndpointsNum(client, "kube-system", "default-http-backend", 1, time.Second*3, time.Minute*10); err != nil { - return errors.Wrap(err, "waiting for one default-http-backend endpoint to be up") - } - - return nil -} - -// WaitForGvisorControllerRunning waits for the gvisor controller pod to be running -func WaitForGvisorControllerRunning(t *testing.T) error { - client, err := commonutil.GetClient() - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - - selector := labels.SelectorFromSet(labels.Set(map[string]string{"kubernetes.io/minikube-addons": "gvisor"})) - if err := commonutil.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { - return errors.Wrap(err, "waiting for gvisor controller pod to stabilize") - } - return nil -} - -// WaitForGvisorControllerDeleted waits for the gvisor controller pod to be deleted -func WaitForGvisorControllerDeleted() error { - client, err := commonutil.GetClient() - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - - selector := labels.SelectorFromSet(labels.Set(map[string]string{"kubernetes.io/minikube-addons": "gvisor"})) - if err := commonutil.WaitForPodDelete(client, "kube-system", selector); err != nil { - return errors.Wrap(err, "waiting for gvisor controller pod deletion") - } - return nil -} - -// WaitForUntrustedNginxRunning waits for the untrusted nginx pod to start running -func WaitForUntrustedNginxRunning() error { - client, err := commonutil.GetClient() - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - - selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"})) - if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { - return errors.Wrap(err, "waiting for nginx pods") - } - return nil -} - -// WaitForFailedCreatePodSandBoxEvent waits for a FailedCreatePodSandBox event to appear -func WaitForFailedCreatePodSandBoxEvent() error { - client, err := commonutil.GetClient() - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - if err := commonutil.WaitForEvent(client, "default", "FailedCreatePodSandBox"); err != nil { - return errors.Wrap(err, "waiting for FailedCreatePodSandBox event") - } - return nil -} - -// WaitForNginxRunning waits for nginx service to be up -func WaitForNginxRunning(t *testing.T) error { - client, err := commonutil.GetClient() - - if err != nil { - return errors.Wrap(err, "getting kubernetes client") - } - - selector := labels.SelectorFromSet(labels.Set(map[string]string{"run": "nginx"})) - if err := commonutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil { - return errors.Wrap(err, "waiting for nginx pods") - } - - if err := commonutil.WaitForService(client, "default", "nginx", true, time.Millisecond*500, time.Minute*10); err != nil { - t.Errorf("Error waiting for nginx service to be up") - } - return nil -} - -// Retry tries the callback for a number of attempts, with a delay between attempts -func Retry(t *testing.T, callback func() error, d time.Duration, attempts int) (err error) { - for i := 0; i < attempts; i++ { - err = callback() - if err == nil { - return nil - } - time.Sleep(d) - } - return err -} diff --git a/test/integration/version_upgrade_test.go b/test/integration/version_upgrade_test.go index 8b92f259cd..9170ec28aa 100644 --- a/test/integration/version_upgrade_test.go +++ b/test/integration/version_upgrade_test.go @@ -18,74 +18,77 @@ package integration import ( "fmt" - "io" - "io/ioutil" "os" + "path/filepath" "runtime" "strings" "testing" + "time" "github.com/docker/machine/libmachine/state" - retryablehttp "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" "k8s.io/minikube/pkg/minikube/constants" - pkgutil "k8s.io/minikube/pkg/util" + "k8s.io/minikube/test/integration/util" ) -func downloadMinikubeBinary(version string) (*os.File, error) { - // Grab latest release binary - url := pkgutil.GetBinaryDownloadURL(version, runtime.GOOS) - resp, err := retryablehttp.Get(url) - if err != nil { - return nil, errors.Wrap(err, "Failed to get latest release binary") - } - defer resp.Body.Close() - - tf, err := ioutil.TempFile("", "minikube") - if err != nil { - return nil, errors.Wrap(err, "Failed to create binary file") - } - _, err = io.Copy(tf, resp.Body) - if err != nil { - return nil, errors.Wrap(err, "Failed to populate temp file") - } - if err := tf.Close(); err != nil { - return nil, errors.Wrap(err, "Failed to close temp file") - } - - if runtime.GOOS != "windows" { - if err := os.Chmod(tf.Name(), 0700); err != nil { - return nil, err - // t.Fatal(errors.Wrap(err, "Failed to make binary executable.")) +func fileExists(fname string) error { + check := func() error { + info, err := os.Stat(fname) + if os.IsNotExist(err) { + return err } + if info.IsDir() { + return fmt.Errorf("Error expect file got dir") + } + return nil } - return tf, err + + if err := util.Retry2(check, 1*time.Second, 3); err != nil { + return errors.Wrap(err, fmt.Sprintf("Failed check if file (%q) exists,", fname)) + } + return nil } // TestVersionUpgrade downloads latest version of minikube and runs with // the odlest supported k8s version and then runs the current head minikube // and it tries to upgrade from the older supported k8s to news supported k8s func TestVersionUpgrade(t *testing.T) { - currentRunner := NewMinikubeRunner(t) - currentRunner.RunCommand("delete", true) - currentRunner.CheckStatus(state.None.String()) - tf, err := downloadMinikubeBinary("latest") - if err != nil || tf == nil { - t.Fatal(errors.Wrap(err, "Failed to download minikube binary.")) + p := profileName(t) + if shouldRunInParallel(t) { + t.Parallel() } - defer os.Remove(tf.Name()) + // fname is the filename for the minikube's latetest binary. this file been pre-downloaded before test by hacks/jenkins/common.sh + fname := filepath.Join(*testdataDir, fmt.Sprintf("minikube-%s-%s-latest-stable", runtime.GOOS, runtime.GOARCH)) + err := fileExists(fname) + if err != nil { // download file if it is not downloaded by other test + dest := filepath.Join(*testdataDir, fmt.Sprintf("minikube-%s-%s-latest-stable", runtime.GOOS, runtime.GOARCH)) + err := downloadMinikubeBinary(t, dest, "latest") + if err != nil { + // binary is needed for the test + t.Fatalf("erorr downloading the latest minikube release %v", err) + } + } + defer os.Remove(fname) - releaseRunner := NewMinikubeRunner(t) - releaseRunner.BinaryPath = tf.Name() + mkCurrent := NewMinikubeRunner(t, p) + defer mkCurrent.TearDown(t) + + mkRelease := NewMinikubeRunner(t, p) + mkRelease.BinaryPath = fname // For full coverage: also test upgrading from oldest to newest supported k8s release - releaseRunner.Start(fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion)) - releaseRunner.CheckStatus(state.Running.String()) - releaseRunner.RunCommand("stop", true) - releaseRunner.CheckStatus(state.Stopped.String()) + stdout, stderr, err := mkRelease.Start(fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion)) + if err != nil { + t.Fatalf("TestVersionUpgrade minikube start failed : %v\nstdout: %s\nstderr: %s", err, stdout, stderr) + } + + mkRelease.CheckStatus(state.Running.String()) + mkRelease.RunCommand("stop", true) + mkRelease.CheckStatus(state.Stopped.String()) // Trim the leading "v" prefix to assert that we handle it properly. - currentRunner.Start(fmt.Sprintf("--kubernetes-version=%s", strings.TrimPrefix(constants.NewestKubernetesVersion, "v"))) - currentRunner.CheckStatus(state.Running.String()) - currentRunner.RunCommand("delete", true) - currentRunner.CheckStatus(state.None.String()) + stdout, stderr, err = mkCurrent.Start(fmt.Sprintf("--kubernetes-version=%s", strings.TrimPrefix(constants.NewestKubernetesVersion, "v"))) + if err != nil { + t.Fatalf("TestVersionUpgrade mkCurrent.Start start failed : %v\nstdout: %s\nstderr: %s", err, stdout, stderr) + } + mkCurrent.CheckStatus(state.Running.String()) } diff --git a/test/integration/proxy_test.go b/test/integration/z_proxy_test.go similarity index 78% rename from test/integration/proxy_test.go rename to test/integration/z_proxy_test.go index 7172528cbe..69a14be0c7 100644 --- a/test/integration/proxy_test.go +++ b/test/integration/z_proxy_test.go @@ -16,6 +16,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +// the name of this file starts with z intentionally to make it run last after all other tests +// the intent is to make sure os env proxy settings be done after all other tests. +// for example in the case the test proxy clean up gets killed or fails package integration import ( @@ -66,20 +69,20 @@ func setUpProxy(t *testing.T) (*http.Server, error) { func TestProxy(t *testing.T) { origHP := os.Getenv("HTTP_PROXY") origNP := os.Getenv("NO_PROXY") + p := profileName(t) // profile name + + if isTestNoneDriver(t) { + // TODO fix this later + t.Skip("Skipping proxy warning for none") + } + srv, err := setUpProxy(t) if err != nil { t.Fatalf("Failed to set up the test proxy: %s", err) } - // making sure there is no running miniukube to avoid https://github.com/kubernetes/minikube/issues/4132 - r := NewMinikubeRunner(t) - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - defer cancel() - _, _, err = r.RunWithContext(ctx, "delete") - if err != nil { - t.Logf("Error deleting minikube before test setup %s : ", err) - } - + // making sure there is no running minikube to avoid https://github.com/kubernetes/minikube/issues/4132 + mk := NewMinikubeRunner(t, p) // Clean up after setting up proxy defer func(t *testing.T) { err = os.Setenv("HTTP_PROXY", origHP) @@ -95,27 +98,23 @@ func TestProxy(t *testing.T) { if err != nil { t.Errorf("Error shutting down the http proxy") } - - _, _, err = r.RunWithContext(ctx, "delete") - if err != nil { - t.Logf("Error deleting minikube when cleaning up proxy setup: %s", err) + if !isTestNoneDriver(t) { + mk.TearDown(t) } - }(t) - t.Run("Proxy Console Warnning", testProxyWarning) - t.Run("Proxy Dashboard", testProxyDashboard) + }(t) + t.Run("ProxyConsoleWarnning", testProxyWarning) + t.Run("ProxyDashboard", testProxyDashboard) } // testProxyWarning checks user is warned correctly about the proxy related env vars func testProxyWarning(t *testing.T) { - r := NewMinikubeRunner(t) - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - defer cancel() - startCmd := fmt.Sprintf("start %s %s %s", r.StartArgs, r.Args, "--alsologtostderr --v=5") - stdout, stderr, err := r.RunWithContext(ctx, startCmd) + p := profileName(t) // profile name + mk := NewMinikubeRunner(t, p) + stdout, stderr, err := mk.Start() if err != nil { - t.Fatalf("start: %v\nstdout: %s\nstderr: %s", err, stdout, stderr) + t.Fatalf("failed to start minikube (for profile %s) failed : %v\nstdout: %s\nstderr: %s", t.Name(), err, stdout, stderr) } msg := "Found network options:" @@ -131,8 +130,9 @@ func testProxyWarning(t *testing.T) { // testProxyDashboard checks if dashboard URL is accessible if proxy is set func testProxyDashboard(t *testing.T) { - minikubeRunner := NewMinikubeRunner(t) - cmd, out := minikubeRunner.RunDaemon("dashboard --url") + p := profileName(t) // profile name + mk := NewMinikubeRunner(t, p) + cmd, out := mk.RunDaemon("dashboard --url") defer func() { err := cmd.Process.Kill() if err != nil { diff --git a/translations/fr-FR.json b/translations/fr-FR.json index 32780d0b08..aac753e008 100644 --- a/translations/fr-FR.json +++ b/translations/fr-FR.json @@ -1,39 +1,42 @@ { - "%q VM does not exist, nothing to stop": "", - "%q cluster does not exist": "", - "%q host does not exist, unable to show an IP": "", - "%q profile does not exist": "", - "%q stopped.": "", - "%s IP has been updated to point at %s": "", - "%s IP was already correctly configured for %s": "", - "%s has no available configuration options": "", - "%s is not responding properly: %v": "", - "%s is not yet a supported filesystem. We will try anyways!": "", - "%s was successfully configured": "", - "%s was successfully disabled": "", - "%s was successfully enabled": "", - "%s:%s is not running: %v": "", + "\"{{.minikube_addon}}\" was successfully disabled": "", + "\"{{.name}}\" cluster does not exist": "", + "\"{{.profile_name}}\" VM does not exist, nothing to stop": "", + "\"{{.profile_name}}\" host does not exist, unable to show an IP": "", + "\"{{.profile_name}}\" profile does not exist": "", + "\"{{.profile_name}}\" stopped.": "", "'none' driver does not support 'minikube docker-env' command": "", "'none' driver does not support 'minikube mount' command": "", "'none' driver does not support 'minikube ssh' command": "", - "Advice: %s": "", - "Alternatively, you may delete the existing VM using `minikube delete -p %s`": "", - "Cannot find directory %s for mount": "", + "==\u003e {{.name}} \u003c==": "", + "A firewall is blocking Docker within the minikube VM from reaching the internet. You may need to configure it to use a proxy.": "", + "A firewall is interfering with minikube's ability to make outgoing HTTPS requests. You may need to change the value of the HTTPS_PROXY environment variable.": "", + "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.": "", + "Alternatively, you may delete the existing VM using `minikube delete -p {{.profile_name}}`": "", + "Cannot find directory {{.path}} for mount": "", "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.": "", + "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'": "", + "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=\u003cswitch-name\u003e` to `minikube start`": "", "Configuring environment for Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}}": "Configurant l'environment pour Kubernetes {{.k8sVersion}} sur {{.runtime}} {{.runtimeVersion}}", "Configuring local host environment ...": "", "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "Créant un VM %s (CPUs=%d, Mémoire=%dMB, Disque=%dMB)", "Creating mount {{.name}} ...": "", - "Deleting %q from %s ...": "", - "Documentation: %s": "", + "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "", + "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Disable Hyper-V when you want to run VirtualBox to boot the VM": "", + "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", + "Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.": "", + "Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.": "", + "Documentation: {{.url}}": "", "Done! kubectl is now configured to use {{.name}}": "Fini! kubectl est maintenant configuré pour utiliser {{.name}}.", "Download complete!": "", - "Downloading %s %s": "", "Downloading Minikube ISO ...": "", + "Downloading {{.name}} {{.version}}": "", "ERROR creating `registry-creds-dpr` secret": "", - "ERROR creating `registry-creds-ecr` secret: %v": "", - "ERROR creating `registry-creds-gcr` secret: %v": "", + "ERROR creating `registry-creds-ecr` secret: {{.error}}": "", + "ERROR creating `registry-creds-gcr` secret: {{.error}}": "", "Enabling dashboard ...": "", + "Error checking driver version: {{.error}}": "", "Error creating list template": "", "Error creating minikube directory": "", "Error creating status template": "", @@ -46,7 +49,7 @@ "Error getting IP": "", "Error getting bootstrapper": "", "Error getting client": "", - "Error getting client: %v": "", + "Error getting client: {{.error}}": "", "Error getting cluster": "", "Error getting cluster bootstrapper": "", "Error getting config": "", @@ -55,29 +58,35 @@ "Error getting machine logs": "", "Error getting machine status": "", "Error getting service status": "", - "Error getting service with namespace: %s and labels %s:%s: %v": "", + "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "", "Error getting the host IP address to use from within the VM": "", "Error host driver ip status": "", "Error killing mount process": "", "Error loading api": "", + "Error loading profile config": "", + "Error loading profile config: {{.error}}": "", "Error opening service": "", - "Error reading %s: %v": "", + "Error parsing minukube version: {{.error}}": "", + "Error parsing vmDriver version: {{.error}}": "", + "Error reading {{.path}}: {{.error}}": "", "Error restarting cluster": "", "Error setting shell variables": "", "Error starting cluster": "", "Error starting mount": "", "Error unsetting shell variables": "", + "Error while setting kubectl current context : {{.error}}": "", "Error writing mount pid": "", - "Error: [%s] %v": "", - "Exiting due to %s signal": "", + "Error: [{{.id}}] {{.error}}": "", + "Failed runtime": "", "Failed to cache ISO": "", "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images": "", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", - "Failed to chown %s: %v": "", + "Failed to chown {{.minikube_dir_path}}: {{.error}}": "", "Failed to delete cluster": "", + "Failed to delete cluster: {{.error}}": "", "Failed to delete images": "", "Failed to delete images from config": "", "Failed to download kubectl": "", @@ -88,8 +97,8 @@ "Failed to get driver URL": "", "Failed to get image map": "", "Failed to get machine client": "", - "Failed to get service URL: %v": "", - "Failed to kill mount process: %v": "", + "Failed to get service URL: {{.error}}": "", + "Failed to kill mount process: {{.error}}": "", "Failed to list cached images": "", "Failed to remove profile": "", "Failed to save config": "", @@ -98,130 +107,175 @@ "Failed to setup kubeconfig": "", "Failed to update cluster": "", "Failed to update config": "", - "Failed unmount: %v": "", + "Failed unmount: {{.error}}": "", "Follow": "", "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", "For more information, see:": "", "Found network options:": "", + "Group ID: {{.groupID}}": "", + "Have you set up libvirt correctly?": "", "If the above advice does not help, please let us know: ": "", - "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": "", - "Invalid size passed in argument: %v": "", + "If using the none driver, ensure that systemctl is installed": "", + "Ignoring --vm-driver={{.driver_name}}, as the existing \"{{.profile_name}}\" VM was created using the {{.driver_name2}} driver.": "", + "In some environments, this message is incorrect. Try 'minikube start --no-vtx-check'": "", + "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver": "", + "Install the latest kvm2 driver and run 'virt-host-validate'": "", + "Install the latest minikube hyperkit driver, and run 'minikube delete'": "", + "Invalid size passed in argument: {{.error}}": "", "IsEnabled failed": "", "Kubernetes downgrade is not supported, will continue to use {{.version}}": "", "Launching Kubernetes ... ": "Lançant Kubernetes ...", "Launching proxy ...": "", - "Mode: %o (%s)": "", - "Mount options:": "", - "Mounting host path %s into VM as %s ...": "", + "Message Size: {{.size}}": "", + "Mount type: {{.name}}": "", + "Mounting host path {{.sourcePath}} into VM as {{.destinationPath}} ...": "", "NOTE: This process must stay alive for the mount to be accessible ...": "", - "None of known repositories in your location is accessible. Use %s as fallback.": "", + "None of known repositories in your location is accessible. Use {{.image_repository_name}} as fallback.": "", "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "", "Opening %s in your default browser...": "", - "Opening kubernetes service %s/%s in default browser...": "", - "Options: %s": "", + "Opening kubernetes service {{.namespace_name}}/{{.service_name}} in default browser...": "", + "Options: {{.options}}": "", + "Permissions: {{.octalMode}} ({{.writtenMode}})": "", + "Please check your BIOS, and ensure that you are running without HyperV or other nested virtualization that may interfere": "", "Please don't run minikube as root or with 'sudo' privileges. It isn't necessary with {{.driver}} driver.": "", "Please enter a value:": "", - "Please run with sudo. the vm-driver %q requires sudo.": "", + "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.": "", + "Please run with sudo. the vm-driver \"{{.driver_name}}\" requires sudo.": "", "Please specify the directory to be mounted: \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "", - "Powering off %q via SSH ...": "", - "Problems detected in %q:": "", + "Please upgrade the 'docker-machine-driver-kvm2'. {{.documentation_url}}": "", + "Powering off \"{{.profile_name}}\" via SSH ...": "", + "Problems detected in {{.entry}}:": "", + "Problems detected in {{.name}}:": "", "Pulling images ...": "Extrayant les images ... ", - "Re-using the currently running %s VM for %q ...": "", + "Re-run 'minikube start' with --alsologtostderr -v=8 to see the VM driver error message": "", + "Re-using the currently running {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", + "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system": "", + "Rebuild libvirt with virt-network support": "", + "Received {{.name}} signal": "", + "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:": "", "Relaunching Kubernetes {{.version}} using {{.bootstrapper}} ... ": "", - "Requested disk size (%dMB) is less than minimum of (%dMB)": "", - "Requested memory allocation (%dMB) is less than the minimum allowed of %dMB": "", - "Requested memory allocation ({{.memory}}MB) is less than the default memory allocation of {{.default}}MB. Beware that minikube might not work correctly or crash unexpectedly.": "", - "Restarting existing %s VM for %q ...": "", + "Requested disk size {{.size_in_mb}} is less than minimum of {{.size_in_mb2}}": "", + "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.": "", + "Requested memory allocation {{.size_in_mb}} is less than the minimum allowed of {{.size_in_mb2}}": "", + "Restarting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", + "Run 'minikube delete' to delete the stale VM": "", + "Run 'minikube delete'. If the problem persists, check your proxy or firewall configuration": "", + "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.": "", + "Run minikube from the C: drive.": "", + "Running on localhost (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "", "Set failed": "", "Setting profile failed": "", - "Skipped switching kubectl context for %s , because --keep-context": "", + "Skipped switching kubectl context for {{.profile_name}} , because --keep-context": "", "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": "", - "Sorry, completion support is not yet implemented for %q": "", - "Sorry, the kubeadm.%s parameter is currently not supported by --extra-config": "", - "Sorry, url provided with --registry-mirror flag is invalid %q": "", - "Stopping %q in %s ...": "", - "Successfully mounted %s to %s": "", - "Target directory %q must be an absolute path": "", - "The %q cluster has been deleted.": "", + "Sorry, completion support is not yet implemented for {{.name}}": "", + "Sorry, the kubeadm.{{.parameter_name}} parameter is currently not supported by --extra-config": "", + "Sorry, url provided with --registry-mirror flag is invalid {{.url}}": "", + "Specify --kubernetes-version in v\u003cmajor\u003e.\u003cminor.\u003cbuild\u003e form. example: 'v1.1.14'": "", + "Specify an alternate --host-only-cidr value, such as 172.16.0.1/24": "", + "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "", + "Suggestion: {{.advice}}": "", + "Target directory {{.path}} must be an absolute path": "", + "The \"{{.cluster_name}}\" cluster has been deleted.": "", + "The 'docker-machine-driver-kvm2' version is old. Please consider upgrading. {{.documentation_url}}": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "", + "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.": "", + "The VM driver exited with an error, and may be corrupt. Run 'minikube start' with --alsologtostderr -v=8 to see the error": "", "The docker host is currently not running": "", "The docker service is currently not active": "", - "The kvm driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the kvm2 driver, which is intended to replace the kvm driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", + "The minikube VM is offline. Please run 'minikube start' to start it again.": "", "The value passed to --format is invalid": "", - "The value passed to --format is invalid: %s": "", - "The vmwarefusion driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", - "The xhyve driver is deprecated and support for it will be removed in a future release.\nPlease consider switching to the hyperkit driver, which is intended to replace the xhyve driver.\nSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver for more information.\nTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", - "There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n": "", + "The value passed to --format is invalid: {{.error}}": "", + "The vmwarefusion driver is deprecated and support for it will be removed in a future release.\n\t\t\tPlease consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver.\n\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information.\n\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", "These changes will take effect upon a minikube delete and then a minikube start": "", - "This addon does not have an endpoint defined for the 'addons open' command.\nYou can add one by annotating a service with the label %s:%s": "", + "This addon does not have an endpoint defined for the 'addons open' command.\nYou can add one by annotating a service with the label {{.labelName}}:{{.addonName}}": "", "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true": "", "Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.": "", - "To connect to this cluster, use: kubectl --context=%s": "", "To connect to this cluster, use: kubectl --context={{.name}}": "", - "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`": "", + "To connect to this cluster, use: kubectl --context={{.profile_name}}": "", + "To disable this notice, run: 'minikube config set WantUpdateNotification false'": "", + "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver={{.driver_name}}`": "", "To use kubectl or minikube commands as your own user, you may": "", - "Type: %s": "", "Unable to bind flags": "", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", "Unable to get VM IP address": "", + "Unable to get bootstrapper: {{.error}}": "", "Unable to get runtime": "", - "Unable to kill mount process: %s": "", + "Unable to kill mount process: {{.error}}": "", "Unable to load cached images from config file.": "", - "Unable to load cached images: %v": "", - "Unable to load config: %v": "", - "Unable to parse %q: %v": "", + "Unable to load cached images: {{.error}}": "", + "Unable to load config: {{.error}}": "", + "Unable to parse \"{{.kubenretes_version}}\": {{.error}}": "", "Unable to pull images, which may be OK: {{.error}}": "", "Unable to start VM": "", "Unable to stop VM": "", - "Uninstalling Kubernetes %s using %s ...": "", - "Unmounting %s ...": "", + "Uninstalling Kubernetes {{.kubernetes_version}} using {{.bootstrapper_name}} ...": "", + "Unmounting {{.path}} ...": "", "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.": "", "Usage: minikube completion SHELL": "", + "User ID: {{.userID}}": "", "Userspace file server is shutdown": "", "Userspace file server: ": "", "Using image repository {{.name}}": "", + "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.": "", "Verifying dashboard health ...": "", "Verifying proxy health ...": "", "Verifying:": "Vérifiant:", - "Version: %s": "", + "Version: {{.version}}": "", "Wait failed": "", - "Wait failed: %v": "", + "Wait failed: {{.error}}": "", "Waiting for SSH access ...": "Attendant l'accès SSH ...", - "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (%s). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details": "", + "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP ({{.ip_address}}). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details": "", "You must specify a service name": "", - "addon '%s' is currently not enabled.\nTo enable this addon run:\nminikube addons enable %s": "", - "addon '%s' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "", + "Your host does not support KVM virtualization. Ensure that qemu-kvm is installed, and run 'virt-host-validate' to debug the problem": "", + "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.": "", + "\\n": "", + "addon '{{.name}}' is currently not enabled.\nTo enable this addon run:\nminikube addons enable {{.name}}": "", + "addon '{{.name}}' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "", "addon list failed": "", "api load": "", "bash completion failed": "", + "browser failed to open url: {{.error}}": "", "command runner": "", "config view failed": "", + "dashboard service is not running: {{.error}}": "", "disable failed": "", - "enable failed: %v": "", + "enable failed": "", + "env {{.docker_env}}": "", "error creating clientset": "", "error creating machine client": "", "error getting driver": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", - "failed to open browser: %v": "", - "kubectl and minikube configuration will be stored in %s": "", + "failed to open browser: {{.error}}": "", + "kube-system": "", + "kubectl and minikube configuration will be stored in {{.home_folder}}": "", + "kubectl has been configured configured to use {{.name}}": "", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", "kubectl proxy": "", "logdir set failed": "", "minikube is not running, so the service cannot be accessed": "", - "minikube profile was successfully set to %s": "", + "minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.": "", + "minikube profile was successfully set to {{.profile_name}}": "", "minikube will upgrade the local cluster from Kubernetes {{.old}} to {{.new}}": "", + "minikube {{.version}} is available! Download it: {{.url}}": "", "minikube {{.version}} on {{.os}} ({{.arch}})": "minikube {{.version}} sur {{.os}} ({{.arch}})", - "mount argument %q must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", + "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "", "need to relocate them. For example, to overwrite your own settings:": "", + "opt {{.docker_option}}": "", + "service {{.namespace_name}}/{{.service_name}} has no node port": "", "stat failed": "", "unable to bind flags": "", "unable to set logtostderr": "", "unset failed": "", - "unsupported driver: %s": "", + "unsupported driver: {{.driver_name}}": "", + "unsupported driver: {{.name}}": "", "update config": "", "usage: minikube addons configure ADDON_NAME": "", "usage: minikube addons disable ADDON_NAME": "", @@ -232,5 +286,18 @@ "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", - "zsh completion failed": "" + "zsh completion failed": "", + "{{.addonName}} was successfully enabled": "", + "{{.error}}": "", + "{{.extra_option_component_name}}.{{.key}}={{.value}}": "", + "{{.key}}={{.value}}": "", + "{{.machine}} IP has been updated to point at {{.ip}}": "", + "{{.machine}} IP was already correctly configured for {{.ip}}": "", + "{{.msg}}: {{.err}}": "", + "{{.name}} cluster does not exist": "", + "{{.name}} has no available configuration options": "", + "{{.name}} was successfully configured": "", + "{{.type}} is not yet a supported filesystem. We will try anyways!": "", + "{{.url}}": "", + "{{.url}} is not accessible: {{.error}}": "" } \ No newline at end of file diff --git a/translations/zh-CN.json b/translations/zh-CN.json index 93c6744a79..b9a194609b 100644 --- a/translations/zh-CN.json +++ b/translations/zh-CN.json @@ -1,39 +1,42 @@ { - "%q VM does not exist, nothing to stop": "", - "%q cluster does not exist": "", - "%q host does not exist, unable to show an IP": "", - "%q profile does not exist": "", - "%q stopped.": "", - "%s IP has been updated to point at %s": "", - "%s IP was already correctly configured for %s": "", - "%s has no available configuration options": "", - "%s is not responding properly: %v": "", - "%s is not yet a supported filesystem. We will try anyways!": "", - "%s was successfully configured": "", - "%s was successfully disabled": "", - "%s was successfully enabled": "", - "%s:%s is not running: %v": "", + "\"{{.minikube_addon}}\" was successfully disabled": "", + "\"{{.name}}\" cluster does not exist": "", + "\"{{.profile_name}}\" VM does not exist, nothing to stop": "", + "\"{{.profile_name}}\" host does not exist, unable to show an IP": "", + "\"{{.profile_name}}\" profile does not exist": "", + "\"{{.profile_name}}\" stopped.": "", "'none' driver does not support 'minikube docker-env' command": "", "'none' driver does not support 'minikube mount' command": "", "'none' driver does not support 'minikube ssh' command": "", - "Advice: %s": "", - "Alternatively, you may delete the existing VM using `minikube delete -p %s`": "", - "Cannot find directory %s for mount": "", + "==\u003e {{.name}} \u003c==": "", + "A firewall is blocking Docker within the minikube VM from reaching the internet. You may need to configure it to use a proxy.": "", + "A firewall is interfering with minikube's ability to make outgoing HTTPS requests. You may need to change the value of the HTTPS_PROXY environment variable.": "", + "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.": "", + "Alternatively, you may delete the existing VM using `minikube delete -p {{.profile_name}}`": "", + "Cannot find directory {{.path}} for mount": "", "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.": "", + "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'": "", + "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=\u003cswitch-name\u003e` to `minikube start`": "", "Configuring environment for Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}}": "开始为Kubernetes {{.k8sVersion}},{{.runtime}} {{.runtimeVersion}} 配置环境变量", "Configuring local host environment ...": "", "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...": "正在创建%s虚拟机(CPU=%d,内存=%dMB,磁盘=%dMB)...", "Creating mount {{.name}} ...": "", - "Deleting %q from %s ...": "", - "Documentation: %s": "", + "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "", + "Deleting \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Disable Hyper-V when you want to run VirtualBox to boot the VM": "", + "Disable dynamic memory in your VM manager, or pass in a larger --memory value": "", + "Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.": "", + "Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.": "", + "Documentation: {{.url}}": "", "Done! kubectl is now configured to use {{.name}}": "完成!kubectl已经配置至{{.name}}", "Download complete!": "", - "Downloading %s %s": "", "Downloading Minikube ISO ...": "", + "Downloading {{.name}} {{.version}}": "", "ERROR creating `registry-creds-dpr` secret": "", - "ERROR creating `registry-creds-ecr` secret: %v": "", - "ERROR creating `registry-creds-gcr` secret: %v": "", + "ERROR creating `registry-creds-ecr` secret: {{.error}}": "", + "ERROR creating `registry-creds-gcr` secret: {{.error}}": "", "Enabling dashboard ...": "", + "Error checking driver version: {{.error}}": "", "Error creating list template": "", "Error creating minikube directory": "", "Error creating status template": "", @@ -46,7 +49,7 @@ "Error getting IP": "", "Error getting bootstrapper": "", "Error getting client": "", - "Error getting client: %v": "", + "Error getting client: {{.error}}": "", "Error getting cluster": "", "Error getting cluster bootstrapper": "", "Error getting config": "", @@ -55,29 +58,35 @@ "Error getting machine logs": "", "Error getting machine status": "", "Error getting service status": "", - "Error getting service with namespace: %s and labels %s:%s: %v": "", + "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}": "", "Error getting the host IP address to use from within the VM": "", "Error host driver ip status": "", "Error killing mount process": "", "Error loading api": "", + "Error loading profile config": "", + "Error loading profile config: {{.error}}": "", "Error opening service": "", - "Error reading %s: %v": "", + "Error parsing minukube version: {{.error}}": "", + "Error parsing vmDriver version: {{.error}}": "", + "Error reading {{.path}}: {{.error}}": "", "Error restarting cluster": "", "Error setting shell variables": "", "Error starting cluster": "", "Error starting mount": "", "Error unsetting shell variables": "", + "Error while setting kubectl current context : {{.error}}": "", "Error writing mount pid": "", - "Error: [%s] %v": "", - "Exiting due to %s signal": "", + "Error: [{{.id}}] {{.error}}": "", + "Failed runtime": "", "Failed to cache ISO": "", "Failed to cache and load images": "", "Failed to cache binaries": "", "Failed to cache images": "", "Failed to check if machine exists": "", "Failed to check main repository and mirrors for images for images": "", - "Failed to chown %s: %v": "", + "Failed to chown {{.minikube_dir_path}}: {{.error}}": "", "Failed to delete cluster": "", + "Failed to delete cluster: {{.error}}": "", "Failed to delete images": "", "Failed to delete images from config": "", "Failed to download kubectl": "", @@ -88,8 +97,8 @@ "Failed to get driver URL": "", "Failed to get image map": "", "Failed to get machine client": "", - "Failed to get service URL: %v": "", - "Failed to kill mount process: %v": "", + "Failed to get service URL: {{.error}}": "", + "Failed to kill mount process: {{.error}}": "", "Failed to list cached images": "", "Failed to remove profile": "", "Failed to save config": "", @@ -98,130 +107,175 @@ "Failed to setup kubeconfig": "", "Failed to update cluster": "", "Failed to update config": "", - "Failed unmount: %v": "", + "Failed unmount: {{.error}}": "", "Follow": "", "For best results, install kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", "For more information, see:": "", "Found network options:": "", + "Group ID: {{.groupID}}": "", + "Have you set up libvirt correctly?": "", "If the above advice does not help, please let us know: ": "", - "Ignoring --vm-driver=%s, as the existing %q VM was created using the %s driver.": "", - "Invalid size passed in argument: %v": "", + "If using the none driver, ensure that systemctl is installed": "", + "Ignoring --vm-driver={{.driver_name}}, as the existing \"{{.profile_name}}\" VM was created using the {{.driver_name2}} driver.": "", + "In some environments, this message is incorrect. Try 'minikube start --no-vtx-check'": "", + "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver": "", + "Install the latest kvm2 driver and run 'virt-host-validate'": "", + "Install the latest minikube hyperkit driver, and run 'minikube delete'": "", + "Invalid size passed in argument: {{.error}}": "", "IsEnabled failed": "", "Kubernetes downgrade is not supported, will continue to use {{.version}}": "", "Launching Kubernetes ... ": "正在启动 Kubernetes ... ", "Launching proxy ...": "", - "Mode: %o (%s)": "", - "Mount options:": "", - "Mounting host path %s into VM as %s ...": "", + "Message Size: {{.size}}": "", + "Mount type: {{.name}}": "", + "Mounting host path {{.sourcePath}} into VM as {{.destinationPath}} ...": "", "NOTE: This process must stay alive for the mount to be accessible ...": "", - "None of known repositories in your location is accessible. Use %s as fallback.": "", + "None of known repositories in your location is accessible. Use {{.image_repository_name}} as fallback.": "", "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag": "", "Opening %s in your default browser...": "", - "Opening kubernetes service %s/%s in default browser...": "", - "Options: %s": "", + "Opening kubernetes service {{.namespace_name}}/{{.service_name}} in default browser...": "", + "Options: {{.options}}": "", + "Permissions: {{.octalMode}} ({{.writtenMode}})": "", + "Please check your BIOS, and ensure that you are running without HyperV or other nested virtualization that may interfere": "", "Please don't run minikube as root or with 'sudo' privileges. It isn't necessary with {{.driver}} driver.": "", "Please enter a value:": "", - "Please run with sudo. the vm-driver %q requires sudo.": "", + "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.": "", + "Please run with sudo. the vm-driver \"{{.driver_name}}\" requires sudo.": "", "Please specify the directory to be mounted: \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "", - "Powering off %q via SSH ...": "", - "Problems detected in %q:": "", + "Please upgrade the 'docker-machine-driver-kvm2'. {{.documentation_url}}": "", + "Powering off \"{{.profile_name}}\" via SSH ...": "", + "Problems detected in {{.entry}}:": "", + "Problems detected in {{.name}}:": "", "Pulling images ...": "拉取镜像 ...", - "Re-using the currently running %s VM for %q ...": "", + "Re-run 'minikube start' with --alsologtostderr -v=8 to see the VM driver error message": "", + "Re-using the currently running {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", + "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system": "", + "Rebuild libvirt with virt-network support": "", + "Received {{.name}} signal": "", + "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:": "", "Relaunching Kubernetes {{.version}} using {{.bootstrapper}} ... ": "", - "Requested disk size (%dMB) is less than minimum of (%dMB)": "", - "Requested memory allocation (%dMB) is less than the minimum allowed of %dMB": "", - "Requested memory allocation ({{.memory}}MB) is less than the default memory allocation of {{.default}}MB. Beware that minikube might not work correctly or crash unexpectedly.": "", - "Restarting existing %s VM for %q ...": "", + "Requested disk size {{.size_in_mb}} is less than minimum of {{.size_in_mb2}}": "", + "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.": "", + "Requested memory allocation {{.size_in_mb}} is less than the minimum allowed of {{.size_in_mb2}}": "", + "Restarting existing {{.driver_name}} VM for \"{{.profile_name}}\" ...": "", + "Run 'minikube delete' to delete the stale VM": "", + "Run 'minikube delete'. If the problem persists, check your proxy or firewall configuration": "", + "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.": "", + "Run minikube from the C: drive.": "", + "Running on localhost (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB, Disk={{.disk_size}}MB) ...": "", "Set failed": "", "Setting profile failed": "", - "Skipped switching kubectl context for %s , because --keep-context": "", + "Skipped switching kubectl context for {{.profile_name}} , because --keep-context": "", "Sorry that minikube crashed. If this was unexpected, we would love to hear from you:": "", - "Sorry, completion support is not yet implemented for %q": "", - "Sorry, the kubeadm.%s parameter is currently not supported by --extra-config": "", - "Sorry, url provided with --registry-mirror flag is invalid %q": "", - "Stopping %q in %s ...": "", - "Successfully mounted %s to %s": "", - "Target directory %q must be an absolute path": "", - "The %q cluster has been deleted.": "", + "Sorry, completion support is not yet implemented for {{.name}}": "", + "Sorry, the kubeadm.{{.parameter_name}} parameter is currently not supported by --extra-config": "", + "Sorry, url provided with --registry-mirror flag is invalid {{.url}}": "", + "Specify --kubernetes-version in v\u003cmajor\u003e.\u003cminor.\u003cbuild\u003e form. example: 'v1.1.14'": "", + "Specify an alternate --host-only-cidr value, such as 172.16.0.1/24": "", + "Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "", + "Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "", + "Suggestion: {{.advice}}": "", + "Target directory {{.path}} must be an absolute path": "", + "The \"{{.cluster_name}}\" cluster has been deleted.": "", + "The 'docker-machine-driver-kvm2' version is old. Please consider upgrading. {{.documentation_url}}": "", "The 'none' driver provides limited isolation and may reduce system security and reliability.": "", + "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.": "", + "The VM driver exited with an error, and may be corrupt. Run 'minikube start' with --alsologtostderr -v=8 to see the error": "", "The docker host is currently not running": "", "The docker service is currently not active": "", - "The kvm driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the kvm2 driver, which is intended to replace the kvm driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", + "The minikube VM is offline. Please run 'minikube start' to start it again.": "", "The value passed to --format is invalid": "", - "The value passed to --format is invalid: %s": "", - "The vmwarefusion driver is deprecated and support for it will be removed in a future release.\n\t\t\t\tPlease consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver.\n\t\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information.\n\t\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", - "The xhyve driver is deprecated and support for it will be removed in a future release.\nPlease consider switching to the hyperkit driver, which is intended to replace the xhyve driver.\nSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver for more information.\nTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", - "There is a newer version of minikube available (%s%s). Download it here:\n%s%s\n\nTo disable this notification, run the following:\nminikube config set WantUpdateNotification false\n": "", + "The value passed to --format is invalid: {{.error}}": "", + "The vmwarefusion driver is deprecated and support for it will be removed in a future release.\n\t\t\tPlease consider switching to the new vmware unified driver, which is intended to replace the vmwarefusion driver.\n\t\t\tSee https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information.\n\t\t\tTo disable this message, run [minikube config set ShowDriverDeprecationNotification false]": "", "These changes will take effect upon a minikube delete and then a minikube start": "", - "This addon does not have an endpoint defined for the 'addons open' command.\nYou can add one by annotating a service with the label %s:%s": "", + "This addon does not have an endpoint defined for the 'addons open' command.\nYou can add one by annotating a service with the label {{.labelName}}:{{.addonName}}": "", "This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true": "", "Tip: Use 'minikube start -p \u003cname\u003e' to create a new cluster, or 'minikube delete' to delete this one.": "", - "To connect to this cluster, use: kubectl --context=%s": "", "To connect to this cluster, use: kubectl --context={{.name}}": "", - "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver=%s`": "", + "To connect to this cluster, use: kubectl --context={{.profile_name}}": "", + "To disable this notice, run: 'minikube config set WantUpdateNotification false'": "", + "To switch drivers, you may create a new VM using `minikube start -p \u003cname\u003e --vm-driver={{.driver_name}}`": "", "To use kubectl or minikube commands as your own user, you may": "", - "Type: %s": "", "Unable to bind flags": "", "Unable to enable dashboard": "", "Unable to fetch latest version info": "", "Unable to get VM IP address": "", + "Unable to get bootstrapper: {{.error}}": "", "Unable to get runtime": "", - "Unable to kill mount process: %s": "", + "Unable to kill mount process: {{.error}}": "", "Unable to load cached images from config file.": "", - "Unable to load cached images: %v": "", - "Unable to load config: %v": "", - "Unable to parse %q: %v": "", + "Unable to load cached images: {{.error}}": "", + "Unable to load config: {{.error}}": "", + "Unable to parse \"{{.kubenretes_version}}\": {{.error}}": "", "Unable to pull images, which may be OK: {{.error}}": "", "Unable to start VM": "", "Unable to stop VM": "", - "Uninstalling Kubernetes %s using %s ...": "", - "Unmounting %s ...": "", + "Uninstalling Kubernetes {{.kubernetes_version}} using {{.bootstrapper_name}} ...": "", + "Unmounting {{.path}} ...": "", "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.": "", "Usage: minikube completion SHELL": "", + "User ID: {{.userID}}": "", "Userspace file server is shutdown": "", "Userspace file server: ": "", "Using image repository {{.name}}": "", + "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.": "", "Verifying dashboard health ...": "", "Verifying proxy health ...": "", "Verifying:": "正在验证:", - "Version: %s": "", + "Version: {{.version}}": "", "Wait failed": "", - "Wait failed: %v": "", + "Wait failed: {{.error}}": "", "Waiting for SSH access ...": "", - "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP (%s). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details": "", + "You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP ({{.ip_address}}). Please see https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md for more details": "", "You must specify a service name": "", - "addon '%s' is currently not enabled.\nTo enable this addon run:\nminikube addons enable %s": "", - "addon '%s' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "", + "Your host does not support KVM virtualization. Ensure that qemu-kvm is installed, and run 'virt-host-validate' to debug the problem": "", + "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.": "", + "\\n": "", + "addon '{{.name}}' is currently not enabled.\nTo enable this addon run:\nminikube addons enable {{.name}}": "", + "addon '{{.name}}' is not a valid addon packaged with minikube.\nTo see the list of available addons run:\nminikube addons list": "", "addon list failed": "", "api load": "", "bash completion failed": "", + "browser failed to open url: {{.error}}": "", "command runner": "", "config view failed": "", + "dashboard service is not running: {{.error}}": "", "disable failed": "", - "enable failed: %v": "", + "enable failed": "", + "env {{.docker_env}}": "", "error creating clientset": "", "error creating machine client": "", "error getting driver": "", "error parsing the input ip address for mount": "", "error starting tunnel": "", - "failed to open browser: %v": "", - "kubectl and minikube configuration will be stored in %s": "", + "failed to open browser: {{.error}}": "", + "kube-system": "", + "kubectl and minikube configuration will be stored in {{.home_folder}}": "", + "kubectl has been configured configured to use {{.name}}": "", "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "", "kubectl proxy": "", "logdir set failed": "", "minikube is not running, so the service cannot be accessed": "", - "minikube profile was successfully set to %s": "", + "minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.": "", + "minikube profile was successfully set to {{.profile_name}}": "", "minikube will upgrade the local cluster from Kubernetes {{.old}} to {{.new}}": "", + "minikube {{.version}} is available! Download it: {{.url}}": "", "minikube {{.version}} on {{.os}} ({{.arch}})": "您正在使用minikube {{.version}}, 运行平台:{{.os}} ({{.arch}})", - "mount argument %q must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", + "mount argument \"{{.value}}\" must be in form: \u003csource directory\u003e:\u003ctarget directory\u003e": "", "mount failed": "", "need to relocate them. For example, to overwrite your own settings:": "", + "opt {{.docker_option}}": "", + "service {{.namespace_name}}/{{.service_name}} has no node port": "", "stat failed": "", "unable to bind flags": "", "unable to set logtostderr": "", "unset failed": "", - "unsupported driver: %s": "", + "unsupported driver: {{.driver_name}}": "", + "unsupported driver: {{.name}}": "", "update config": "", "usage: minikube addons configure ADDON_NAME": "", "usage: minikube addons disable ADDON_NAME": "", @@ -232,5 +286,18 @@ "usage: minikube config unset PROPERTY_NAME": "", "usage: minikube delete": "", "usage: minikube profile [MINIKUBE_PROFILE_NAME]": "", - "zsh completion failed": "" + "zsh completion failed": "", + "{{.addonName}} was successfully enabled": "", + "{{.error}}": "", + "{{.extra_option_component_name}}.{{.key}}={{.value}}": "", + "{{.key}}={{.value}}": "", + "{{.machine}} IP has been updated to point at {{.ip}}": "", + "{{.machine}} IP was already correctly configured for {{.ip}}": "", + "{{.msg}}: {{.err}}": "", + "{{.name}} cluster does not exist": "", + "{{.name}} has no available configuration options": "", + "{{.name}} was successfully configured": "", + "{{.type}} is not yet a supported filesystem. We will try anyways!": "", + "{{.url}}": "", + "{{.url}} is not accessible: {{.error}}": "" } \ No newline at end of file