Merge remote-tracking branch 'upstream/master'

pull/4283/head
tstromberg 2019-05-17 10:47:34 -07:00
commit 7c100538e8
94 changed files with 1149 additions and 936 deletions

View File

@ -5,6 +5,8 @@ sudo: required
go: go:
- 1.x - 1.x
before_install:
- sudo apt-get install -y libvirt-dev
install: install:
- echo "Don't run anything." - echo "Don't run anything."
script: script:

View File

@ -219,9 +219,25 @@ fmt:
vet: vet:
@go vet $(SOURCE_PACKAGES) @go vet $(SOURCE_PACKAGES)
# Once v1.16.1+ is released, replace with
# curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh \
# | bash -s -- -b out/linters v1.16.0
out/linters/golangci-lint:
mkdir -p out/linters \
&& cd out/linters \
&& test -f go.mod || go mod init linters \
&& go get -u github.com/golangci/golangci-lint/cmd/golangci-lint@692dacb773b703162c091c2d8c59f9cd2d6801db >/dev/null
cp -f $(GOPATH)/bin/golangci-lint out/linters/golangci-lint
.PHONY: lint .PHONY: lint
lint: lint: pkg/minikube/assets/assets.go out/linters/golangci-lint
@golint -set_exit_status $(SOURCE_PACKAGES) ./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' \
./...
.PHONY: reportcard .PHONY: reportcard
reportcard: reportcard:

View File

@ -56,16 +56,16 @@ For the list of accessible variables for the template, see the struct values her
cacheCmd.AddCommand(listCacheCmd) cacheCmd.AddCommand(listCacheCmd)
} }
// cacheList returns a formatted list of images found within the local cache
func cacheList(images []string) error { func cacheList(images []string) error {
for _, image := range images { for _, image := range images {
tmpl, err := template.New("list").Parse(cacheListFormat) tmpl, err := template.New("list").Parse(cacheListFormat)
if err != nil { if err != nil {
exit.WithError("Unable to parse template", err) return err
} }
listTmplt := CacheListTemplate{image} listTmplt := CacheListTemplate{image}
err = tmpl.Execute(os.Stdout, listTmplt) if err := tmpl.Execute(os.Stdout, listTmplt); err != nil {
if err != nil { return err
exit.WithError("Unable to process template", err)
} }
} }
return nil return nil

View File

@ -17,6 +17,7 @@ limitations under the License.
package config package config
import ( import (
"github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,6 +27,8 @@ var AddonsCmd = &cobra.Command{
Short: "Modify minikube's kubernetes addons", Short: "Modify minikube's kubernetes addons",
Long: `addons modifies minikube addons files using subcommands like "minikube addons enable heapster"`, Long: `addons modifies minikube addons files using subcommands like "minikube addons enable heapster"`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmd.Help() if err := cmd.Help(); err != nil {
glog.Errorf("help: %v", err)
}
}, },
} }

View File

@ -23,6 +23,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
@ -261,7 +262,9 @@ var ConfigCmd = &cobra.Command{
Long: `config modifies minikube config files using subcommands like "minikube config set vm-driver kvm" Long: `config modifies minikube config files using subcommands like "minikube config set vm-driver kvm"
Configurable fields: ` + "\n\n" + configurableFields(), Configurable fields: ` + "\n\n" + configurableFields(),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmd.Help() if err := cmd.Help(); err != nil {
glog.Errorf("help: %v", err)
}
}, },
} }
@ -344,12 +347,12 @@ func DeleteFromConfigMap(name string, images []string) error {
func WriteConfig(m config.MinikubeConfig) error { func WriteConfig(m config.MinikubeConfig) error {
f, err := os.Create(constants.ConfigFile) f, err := os.Create(constants.ConfigFile)
if err != nil { if err != nil {
return fmt.Errorf("Could not open file %s: %s", constants.ConfigFile, err) return fmt.Errorf("create %s: %s", constants.ConfigFile, err)
} }
defer f.Close() defer f.Close()
err = encode(f, m) err = encode(f, m)
if err != nil { if err != nil {
return fmt.Errorf("Error encoding config %s: %s", constants.ConfigFile, err) return fmt.Errorf("encode %s: %s", constants.ConfigFile, err)
} }
return nil return nil
} }

View File

@ -95,9 +95,9 @@ You can add one by annotating a service with the label %s:%s`, key, addonName)
} }
for i := range serviceList.Items { for i := range serviceList.Items {
svc := serviceList.Items[i].ObjectMeta.Name svc := serviceList.Items[i].ObjectMeta.Name
service.WaitAndMaybeOpenService(api, namespace, svc, addonsURLTemplate, if err := service.WaitAndMaybeOpenService(api, namespace, svc, addonsURLTemplate, addonsURLMode, https, wait, interval); err != nil {
addonsURLMode, https, wait, interval) exit.WithCode(exit.Unavailable, "Wait failed: %v", err)
}
} }
}, },
} }

View File

@ -23,6 +23,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/golang/glog"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
"k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/console"
) )
@ -42,15 +43,13 @@ func AskForYesNoConfirmation(s string, posResponses, negResponses []string) bool
log.Fatal(err) log.Fatal(err)
} }
response = strings.ToLower(strings.TrimSpace(response)) switch r := strings.ToLower(strings.TrimSpace(response)); {
case containsString(posResponses, r):
if containsString(posResponses, response) {
return true return true
} else if containsString(negResponses, response) { case containsString(negResponses, r):
return false return false
} else { default:
console.Err("Please type yes or no:") console.Err("Please type yes or no:")
return AskForYesNoConfirmation(s, posResponses, negResponses)
} }
} }
} }
@ -112,7 +111,7 @@ func concealableAskForStaticValue(readWriter io.ReadWriter, promptString string,
response = strings.TrimSpace(response) response = strings.TrimSpace(response)
if len(response) == 0 { if len(response) == 0 {
console.Warning("Please enter a value:") console.Warning("Please enter a value:")
return concealableAskForStaticValue(readWriter, promptString, hidden) continue
} }
return response, nil return response, nil
} }
@ -126,7 +125,11 @@ func AskForPasswordValue(s string) string {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer terminal.Restore(stdInFd, oldState) defer func() {
if err := terminal.Restore(stdInFd, oldState); err != nil {
glog.Errorf("terminal restore failed: %v", err)
}
}()
result, err := concealableAskForStaticValue(os.Stdin, s, true) result, err := concealableAskForStaticValue(os.Stdin, s, true)
if err != nil { if err != nil {

View File

@ -54,7 +54,7 @@ func findSetting(name string) (Setting, error) {
return s, nil return s, nil
} }
} }
return Setting{}, fmt.Errorf("Property name %s not found", name) return Setting{}, fmt.Errorf("property name %q not found", name)
} }
// Set Functions // Set Functions

View File

@ -33,6 +33,16 @@ import (
"k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/cruntime"
) )
// containerdOnlyMsg is the message shown when a containerd-only addon is enabled
const containerdOnlyAddonMsg = `
This addon can only be enabled with the containerd runtime backend. To enable this backend, please first stop minikube with:
minikube stop
and then start minikube again with the following flags:
minikube start --container-runtime=containerd --docker-opt containerd=/var/run/containerd/containerd.sock`
// IsValidDriver checks if a driver is supported // IsValidDriver checks if a driver is supported
func IsValidDriver(string, driver string) error { func IsValidDriver(string, driver string) error {
for _, d := range constants.SupportedVMDrivers { for _, d := range constants.SupportedVMDrivers {
@ -40,7 +50,7 @@ func IsValidDriver(string, driver string) error {
return nil return nil
} }
} }
return fmt.Errorf("Driver %s is not supported", driver) return fmt.Errorf("driver %q is not supported", driver)
} }
// RequiresRestartMsg returns the "requires restart" message // RequiresRestartMsg returns the "requires restart" message
@ -53,7 +63,7 @@ func RequiresRestartMsg(string, string) error {
func IsValidDiskSize(name string, disksize string) error { func IsValidDiskSize(name string, disksize string) error {
_, err := units.FromHumanSize(disksize) _, err := units.FromHumanSize(disksize)
if err != nil { if err != nil {
return fmt.Errorf("Not valid disk size: %v", err) return fmt.Errorf("invalid disk size: %v", err)
} }
return nil return nil
} }
@ -117,7 +127,7 @@ func IsPositive(name string, val string) error {
func IsValidCIDR(name string, cidr string) error { func IsValidCIDR(name string, cidr string) error {
_, _, err := net.ParseCIDR(cidr) _, _, err := net.ParseCIDR(cidr)
if err != nil { if err != nil {
return fmt.Errorf("Error parsing CIDR: %v", err) return fmt.Errorf("invalid CIDR: %v", err)
} }
return nil return nil
} }
@ -151,16 +161,7 @@ func IsContainerdRuntime(_, _ string) error {
} }
_, ok := r.(*cruntime.Containerd) _, ok := r.(*cruntime.Containerd)
if !ok { if !ok {
return fmt.Errorf(`This addon can only be enabled with the containerd runtime backend. return fmt.Errorf(containerdOnlyAddonMsg)
To enable this backend, please first stop minikube with:
minikube stop
and then start minikube again with the following flags:
minikube start --container-runtime=containerd --docker-opt containerd=/var/run/containerd/containerd.sock`)
} }
return nil return nil
} }

View File

@ -377,7 +377,9 @@ var dockerEnvCmd = &cobra.Command{
} }
} }
executeTemplateStdout(shellCfg) if err := executeTemplateStdout(shellCfg); err != nil {
exit.WithError("Error executing template", err)
}
}, },
} }

View File

@ -86,7 +86,9 @@ var RootCmd = &cobra.Command{
logDir := pflag.Lookup("log_dir") logDir := pflag.Lookup("log_dir")
if !logDir.Changed { if !logDir.Changed {
logDir.Value.Set(constants.MakeMiniPath("logs")) if err := logDir.Value.Set(constants.MakeMiniPath("logs")); err != nil {
exit.WithError("logdir set failed", err)
}
} }
if enableUpdateNotification { if enableUpdateNotification {
@ -116,7 +118,9 @@ func setFlagsUsingViper() {
} }
// Viper will give precedence first to calls to the Set command, // Viper will give precedence first to calls to the Set command,
// then to values from the config.yml // then to values from the config.yml
a.Value.Set(viper.GetString(a.Name)) if err := a.Value.Set(viper.GetString(a.Name)); err != nil {
exit.WithError(fmt.Sprintf("failed to set value for %q", a.Name), err)
}
a.Changed = true a.Changed = true
} }
} }
@ -129,7 +133,9 @@ func init() {
RootCmd.AddCommand(configCmd.AddonsCmd) RootCmd.AddCommand(configCmd.AddonsCmd)
RootCmd.AddCommand(configCmd.ProfileCmd) RootCmd.AddCommand(configCmd.ProfileCmd)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
viper.BindPFlags(RootCmd.PersistentFlags()) if err := viper.BindPFlags(RootCmd.PersistentFlags()); err != nil {
exit.WithError("Unable to bind flags", err)
}
cobra.OnInitialize(initConfig) cobra.OnInitialize(initConfig)
@ -176,7 +182,7 @@ func GetClusterBootstrapper(api libmachine.API, bootstrapperName string) (bootst
return nil, errors.Wrap(err, "getting kubeadm bootstrapper") return nil, errors.Wrap(err, "getting kubeadm bootstrapper")
} }
default: default:
return nil, fmt.Errorf("Unknown bootstrapper: %s", bootstrapperName) return nil, fmt.Errorf("unknown bootstrapper: %s", bootstrapperName)
} }
return b, nil return b, nil

View File

@ -22,6 +22,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -145,37 +146,43 @@ func getEnvVarName(name string) string {
return constants.MinikubeEnvPrefix + "_" + strings.ToUpper(name) return constants.MinikubeEnvPrefix + "_" + strings.ToUpper(name)
} }
func setValues(t *testing.T, tt configTest) { func setValues(tt configTest) error {
if tt.FlagValue != "" { if tt.FlagValue != "" {
pflag.Set(tt.Name, tt.FlagValue) if err := pflag.Set(tt.Name, tt.FlagValue); err != nil {
return errors.Wrap(err, "flag set")
}
} }
if tt.EnvValue != "" { if tt.EnvValue != "" {
s := strings.Replace(getEnvVarName(tt.Name), "-", "_", -1) s := strings.Replace(getEnvVarName(tt.Name), "-", "_", -1)
os.Setenv(s, tt.EnvValue) os.Setenv(s, tt.EnvValue)
} }
if tt.ConfigValue != "" { if tt.ConfigValue != "" {
err := initTestConfig(tt.ConfigValue) if err := initTestConfig(tt.ConfigValue); err != nil {
if err != nil { return errors.Wrapf(err, "Config %s not read correctly", tt.ConfigValue)
t.Fatalf("Config %s not read correctly: %v", tt.ConfigValue, err)
} }
} }
return nil
} }
func unsetValues(tt configTest) { func unsetValues(name string) error {
var f = pflag.Lookup(tt.Name) f := pflag.Lookup(name)
f.Value.Set(f.DefValue) if err := f.Value.Set(f.DefValue); err != nil {
return errors.Wrapf(err, "set(%s)", f.DefValue)
}
f.Changed = false f.Changed = false
os.Unsetenv(getEnvVarName(name))
os.Unsetenv(getEnvVarName(tt.Name))
viper.Reset() viper.Reset()
return nil
} }
func TestViperAndFlags(t *testing.T) { func TestViperAndFlags(t *testing.T) {
restore := hideEnv(t) restore := hideEnv(t)
defer restore(t) defer restore(t)
for _, tt := range configTests { for _, tt := range configTests {
setValues(t, tt) err := setValues(tt)
if err != nil {
t.Fatalf("setValues: %v", err)
}
setupViper() setupViper()
f := pflag.Lookup(tt.Name) f := pflag.Lookup(tt.Name)
if f == nil { if f == nil {
@ -185,6 +192,9 @@ func TestViperAndFlags(t *testing.T) {
if actual != tt.ExpectedValue { if actual != tt.ExpectedValue {
t.Errorf("pflag.Value(%s) => %s, wanted %s [%+v]", tt.Name, actual, tt.ExpectedValue, tt) t.Errorf("pflag.Value(%s) => %s, wanted %s [%+v]", tt.Name, actual, tt.ExpectedValue, tt)
} }
unsetValues(tt) // Some flag validation may not accept their default value, such as log_at_backtrace :(
if err := unsetValues(tt.Name); err != nil {
t.Logf("unsetValues(%s) failed: %v", tt.Name, err)
}
} }
} }

View File

@ -22,7 +22,7 @@ import (
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/api/core/v1" core "k8s.io/api/core/v1"
"k8s.io/minikube/pkg/minikube/console" "k8s.io/minikube/pkg/minikube/console"
"k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/pkg/minikube/machine"
@ -69,6 +69,6 @@ var serviceListCmd = &cobra.Command{
} }
func init() { func init() {
serviceListCmd.Flags().StringVarP(&serviceListNamespace, "namespace", "n", v1.NamespaceAll, "The services namespace") serviceListCmd.Flags().StringVarP(&serviceListNamespace, "namespace", "n", core.NamespaceAll, "The services namespace")
serviceCmd.AddCommand(serviceListCmd) serviceCmd.AddCommand(serviceListCmd)
} }

View File

@ -32,7 +32,6 @@ import (
"github.com/blang/semver" "github.com/blang/semver"
"github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/name"
@ -153,7 +152,9 @@ func init() {
startCmd.Flags().Bool(gpu, false, "Enable experimental NVIDIA GPU support in minikube (works only with kvm2 driver on Linux)") startCmd.Flags().Bool(gpu, false, "Enable experimental NVIDIA GPU support in minikube (works only with kvm2 driver on Linux)")
startCmd.Flags().Bool(hidden, false, "Hide the hypervisor signature from the guest in minikube (works only with kvm2 driver on Linux)") startCmd.Flags().Bool(hidden, false, "Hide the hypervisor signature from the guest in minikube (works only with kvm2 driver on Linux)")
startCmd.Flags().Bool(noVTXCheck, false, "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox)") startCmd.Flags().Bool(noVTXCheck, false, "Disable checking for the availability of hardware virtualization before the vm is started (virtualbox)")
viper.BindPFlags(startCmd.Flags()) if err := viper.BindPFlags(startCmd.Flags()); err != nil {
exit.WithError("unable to bind flags", err)
}
RootCmd.AddCommand(startCmd) RootCmd.AddCommand(startCmd)
} }
@ -232,7 +233,7 @@ func runStart(cmd *cobra.Command, args []string) {
exit.WithError("Failed to get command runner", err) exit.WithError("Failed to get command runner", err)
} }
cr := configureRuntimes(host, runner, k8sVersion) cr := configureRuntimes(runner, k8sVersion)
// prepareHostEnvironment uses the downloaded images, so we need to wait for background task completion. // prepareHostEnvironment uses the downloaded images, so we need to wait for background task completion.
waitCacheImages(&cacheGroup) waitCacheImages(&cacheGroup)
@ -242,9 +243,6 @@ func runStart(cmd *cobra.Command, args []string) {
// The kube config must be update must come before bootstrapping, otherwise health checks may use a stale IP // The kube config must be update must come before bootstrapping, otherwise health checks may use a stale IP
kubeconfig := updateKubeConfig(host, &config) kubeconfig := updateKubeConfig(host, &config)
bootstrapCluster(bs, cr, runner, config.KubernetesConfig, preexisting, isUpgrade) bootstrapCluster(bs, cr, runner, config.KubernetesConfig, preexisting, isUpgrade)
apiserverPort := config.KubernetesConfig.NodePort
validateCluster(bs, cr, runner, ip, apiserverPort)
configureMounts() configureMounts()
if err = LoadCachedImagesInConfigFile(); err != nil { if err = LoadCachedImagesInConfigFile(); err != nil {
console.Failure("Unable to load cached images from config file.") console.Failure("Unable to load cached images from config file.")
@ -255,6 +253,9 @@ func runStart(cmd *cobra.Command, args []string) {
prepareNone() prepareNone()
} }
if err := bs.WaitCluster(config.KubernetesConfig); err != nil {
exit.WithError("Wait failed", err)
}
showKubectlConnectInfo(kubeconfig) showKubectlConnectInfo(kubeconfig)
} }
@ -277,7 +278,7 @@ func selectImageRepository(mirrorCountry string, k8sVersion string) (bool, strin
if mirrorCountry != "" { if mirrorCountry != "" {
localRepos, ok := constants.ImageRepositories[mirrorCountry] localRepos, ok := constants.ImageRepositories[mirrorCountry]
if !ok || len(localRepos) <= 0 { if !ok || len(localRepos) == 0 {
return false, "", fmt.Errorf("invalid image mirror country code: %s", mirrorCountry) return false, "", fmt.Errorf("invalid image mirror country code: %s", mirrorCountry)
} }
@ -504,7 +505,7 @@ func startHost(api libmachine.API, mc cfg.MachineConfig) (*host.Host, bool) {
start := func() (err error) { start := func() (err error) {
host, err = cluster.StartHost(api, mc) host, err = cluster.StartHost(api, mc)
if err != nil { if err != nil {
glog.Infof("StartHost: %v", err) glog.Errorf("StartHost: %v", err)
} }
return err return err
} }
@ -617,7 +618,7 @@ func updateKubeConfig(h *host.Host, c *cfg.Config) *pkgutil.KubeConfigSetup {
} }
// configureRuntimes does what needs to happen to get a runtime going. // configureRuntimes does what needs to happen to get a runtime going.
func configureRuntimes(h *host.Host, runner bootstrapper.CommandRunner, k8sVersion string) cruntime.Manager { func configureRuntimes(runner cruntime.CommandRunner, k8sVersion string) cruntime.Manager {
config := cruntime.Config{Type: viper.GetString(containerRuntime), Runner: runner} config := cruntime.Config{Type: viper.GetString(containerRuntime), Runner: runner}
cr, err := cruntime.New(config) cr, err := cruntime.New(config)
if err != nil { if err != nil {
@ -666,34 +667,6 @@ func bootstrapCluster(bs bootstrapper.Bootstrapper, r cruntime.Manager, runner b
} }
} }
// validateCluster validates that the cluster is well-configured and healthy
func validateCluster(bs bootstrapper.Bootstrapper, r cruntime.Manager, runner bootstrapper.CommandRunner, ip string, apiserverPort int) {
k8sStat := func() (err error) {
st, err := bs.GetKubeletStatus()
if err != nil || st != state.Running.String() {
return &pkgutil.RetriableError{Err: fmt.Errorf("kubelet unhealthy: %v: %s", err, st)}
}
return nil
}
err := pkgutil.RetryAfter(20, k8sStat, 3*time.Second)
if err != nil {
exit.WithLogEntries("kubelet checks failed", err, logs.FindProblems(r, bs, runner))
}
aStat := func() (err error) {
st, err := bs.GetAPIServerStatus(net.ParseIP(ip), apiserverPort)
if err != nil || st != state.Running.String() {
return &pkgutil.RetriableError{Err: fmt.Errorf("apiserver status=%s err=%v", st, err)}
}
return nil
}
err = pkgutil.RetryAfter(30, aStat, 10*time.Second)
if err != nil {
exit.WithLogEntries("apiserver checks failed", err, logs.FindProblems(r, bs, runner))
}
console.OutLn("")
}
// configureMounts configures any requested filesystem mounts // configureMounts configures any requested filesystem mounts
func configureMounts() { func configureMounts() {
if !viper.GetBool(createMount) { if !viper.GetBool(createMount) {

View File

@ -31,12 +31,12 @@ func main() {
func validateSchema(schemaPathString string, docPathString string) { func validateSchema(schemaPathString string, docPathString string) {
schemaPath, _ := filepath.Abs(schemaPathString) schemaPath, _ := filepath.Abs(schemaPathString)
schemaUri := "file://" + schemaPath schemaSrc := "file://" + schemaPath
schemaLoader := gojsonschema.NewReferenceLoader(schemaUri) schemaLoader := gojsonschema.NewReferenceLoader(schemaSrc)
docPath, _ := filepath.Abs(docPathString) docPath, _ := filepath.Abs(docPathString)
docUri := "file://" + docPath docSrc := "file://" + docPath
docLoader := gojsonschema.NewReferenceLoader(docUri) docLoader := gojsonschema.NewReferenceLoader(docSrc)
result, err := gojsonschema.Validate(schemaLoader, docLoader) result, err := gojsonschema.Validate(schemaLoader, docLoader)
if err != nil { if err != nil {

View File

@ -10,6 +10,12 @@ The `none` driver allows advanced minikube users to skip VM creation, allowing m
The `none` driver supports releases of Debian, Ubuntu, and Fedora that are less than 2 years old. In practice, any systemd-based modern distribution is likely to work, and we will accept pull requests which improve compatibility with other systems. The `none` driver supports releases of Debian, Ubuntu, and Fedora that are less than 2 years old. In practice, any systemd-based modern distribution is likely to work, and we will accept pull requests which improve compatibility with other systems.
## Example: basic usage
`sudo minikube start`
NOTE: The none driver requires minikube to be run as root, until [#3760](https://github.com/kubernetes/minikube/issues/3760) can be addressed.
## Example: Using minikube for continuous integration testing ## Example: Using minikube for continuous integration testing
Most continuous integration environments are already running inside a VM, and may not supported nested virtualization. The `none` driver was designed for this use case. Here is an example, that runs minikube from a non-root user, and ensures that the latest stable kubectl is installed: Most continuous integration environments are already running inside a VM, and may not supported nested virtualization. The `none` driver was designed for this use case. Here is an example, that runs minikube from a non-root user, and ensures that the latest stable kubectl is installed:

114
go.mod
View File

@ -3,94 +3,100 @@ module k8s.io/minikube
go 1.12 go 1.12
require ( require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Parallels/docker-machine-parallels v1.3.0 github.com/Parallels/docker-machine-parallels v1.3.0
github.com/Sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 // indirect
github.com/blang/semver v3.5.0+incompatible github.com/blang/semver v3.5.0+incompatible
github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 // indirect
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/cpuguy83/go-md2man v1.0.4 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect
github.com/davecgh/go-spew v0.0.0-20170626231645-782f4967f2dc github.com/cpuguy83/go-md2man v1.0.4 // indirect
github.com/docker/docker v0.0.0-20180917213351-bbe08dc7f0b9 github.com/docker/docker v1.13.1 // indirect
github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69 github.com/docker/go-units v0.0.0-20170127094116-9e638d38cf69
github.com/docker/machine v0.16.1 github.com/docker/machine v0.16.1
github.com/fsnotify/fsnotify v0.0.0-20160816051541-f12c6236fe7b github.com/fatih/color v1.7.0 // indirect
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 // indirect
github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e // indirect
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c github.com/golang/glog v0.0.0-20141105023935-44145f04b68c
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 // indirect
github.com/golang/protobuf v1.2.0 github.com/google/btree v1.0.0 // indirect
github.com/google/btree v1.0.0
github.com/google/go-cmp v0.2.0 github.com/google/go-cmp v0.2.0
github.com/google/go-containerregistry v0.0.0-20190318164241-019cdfc6adf9 github.com/google/go-containerregistry v0.0.0-20190318164241-019cdfc6adf9
github.com/google/go-github/v25 v25.0.2 github.com/google/go-github/v25 v25.0.2
github.com/google/go-querystring v1.0.0 github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 // indirect
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d // indirect
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d github.com/gorilla/mux v1.7.1 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce // indirect
github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 github.com/hashicorp/go-multierror v0.0.0-20160811015721-8c5f0ad93604 // indirect
github.com/hashicorp/go-version v1.1.0 github.com/hashicorp/go-version v1.1.0 // indirect
github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 // indirect
github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1 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/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8
github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 // indirect
github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b github.com/jimmidyson/go-download v0.0.0-20161028105827-7f9a90c8c95b
github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345 github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345
github.com/json-iterator/go v1.1.5 github.com/json-iterator/go v1.1.5 // indirect
github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 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/libvirt/libvirt-go v3.4.0+incompatible
github.com/machine-drivers/docker-machine-driver-vmware v0.1.1 github.com/machine-drivers/docker-machine-driver-vmware v0.1.1
github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4 github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4 // indirect
github.com/mattn/go-isatty v0.0.4 github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-runewidth v0.0.0-20161012013512-737072b4e32b 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/go-ps v0.0.0-20170309133038-4fdf99ab2936
github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49 github.com/mitchellh/mapstructure v0.0.0-20170307201123-53818660ed49 // indirect
github.com/moby/hyperkit v0.0.0-20171020124204-a12cd7250bcd github.com/moby/hyperkit v0.0.0-20171020124204-a12cd7250bcd
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd 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/pborman/uuid v0.0.0-20150603214016-ca53cad383ca github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca
github.com/pelletier/go-buffruneio v0.1.0 github.com/pelletier/go-buffruneio v0.1.0 // indirect
github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4 github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4 // indirect
github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible
github.com/pkg/browser v0.0.0-20160118053552-9302be274faa github.com/pkg/browser v0.0.0-20160118053552-9302be274faa
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.8.0
github.com/pkg/profile v0.0.0-20161223203901-3a8809bd8a80 github.com/pkg/profile v0.0.0-20161223203901-3a8809bd8a80
github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6 github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6 // indirect
github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib v1.0.0
github.com/r2d4/external-storage v0.0.0-20171222174501-8c0e8605dc7b github.com/r2d4/external-storage v0.0.0-20171222174501-8c0e8605dc7b
github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5 github.com/russross/blackfriday v0.0.0-20151117072312-300106c228d5 // indirect
github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 // indirect
github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db github.com/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db // indirect
github.com/sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 github.com/sirupsen/logrus v1.4.1
github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97 github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97 // indirect
github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a // indirect
github.com/spf13/cobra v0.0.0-20180228053838-6644d46b81fa github.com/spf13/cobra v0.0.0-20180228053838-6644d46b81fa
github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80 github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80 // indirect
github.com/spf13/pflag v1.0.1 github.com/spf13/pflag v1.0.1
github.com/spf13/viper v1.0.0 github.com/spf13/viper v1.0.0
github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 github.com/stretchr/testify v1.3.0 // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c 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/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be
github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20190311183353-d8887717615a
golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
golang.org/x/text v0.3.2 golang.org/x/text v0.3.2
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d golang.org/x/time v0.0.0-20161028155119-f51c12702a4d // indirect
google.golang.org/appengine v1.4.0 gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.6 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/inf.v0 v0.9.0 gopkg.in/cheggaaa/pb.v1 v1.0.6 // indirect
gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054 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/api v0.0.0-20180712090710-2d6f90ab1293
k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d
k8s.io/apiserver v0.0.0-20180914001516-67c892841170 k8s.io/apiserver v0.0.0-20180914001516-67c892841170 // indirect
k8s.io/client-go v0.0.0-20180806134042-1f13a808da65 k8s.io/client-go v0.0.0-20180806134042-1f13a808da65
k8s.io/kube-openapi v0.0.0-20180216212618-50ae88d24ede k8s.io/kube-openapi v0.0.0-20180216212618-50ae88d24ede // indirect
k8s.io/kubernetes v1.11.3 k8s.io/kubernetes v1.11.3
) )

85
go.sum
View File

@ -3,24 +3,31 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7O
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Parallels/docker-machine-parallels v1.3.0 h1:RG1fyf3v1GwXMCeHRiZkB4tL9phFZEv6ixcvRZ1raN8= 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/Parallels/docker-machine-parallels v1.3.0/go.mod h1:HCOMm3Hulq/xuEVQMyZOuQlA+dSZpFY5kdCTZWjMVis=
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/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= 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/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9 h1:+ziP/wVJWuAORkjv7386TRidVKY57X0bXBZFMeFlW+U= 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/c4milo/gotoolkit v0.0.0-20170318115440-bcc06269efa9/go.mod h1:txokOny9wavBtq2PWuHmj1P+eFwpCsj+gQeNNANChfU=
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:Yg2hDs4b13Evkpj42FU2idX2cVXVFqQSheXYKM86Qsk= 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-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/cpuguy83/go-md2man v1.0.4 h1:OwjhDpK9YGCcI5CDf8HcdfsXqr6znFyAJfuZ27ixJsc=
github.com/cpuguy83/go-md2man v1.0.4/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY= github.com/cpuguy83/go-md2man v1.0.4/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY=
github.com/davecgh/go-spew v0.0.0-20170626231645-782f4967f2dc h1:0A0n6a0Y3vW5ktoWKC+ggkGXRzMJWMvqIYlFmsjwQzY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v0.0.0-20170626231645-782f4967f2dc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/docker/docker v0.0.0-20180917213351-bbe08dc7f0b9 h1:dArdEP6A7F7aoAph4Gs505ME7QSBjjbRdpklFV384KU= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/docker v0.0.0-20180917213351-bbe08dc7f0b9/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-units v0.0.0-20170127094116-9e638d38cf69 h1:N4WAsrRIb+4U1yIwJO3FMrLnrr61ael894nygpViQTU= 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/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 h1:zrgroZounGVkxLmBqMyc1uT2GgapXVjIWHCfBf0udrA=
github.com/docker/machine v0.16.1/go.mod h1:I8mPNDeK1uH+JTcUU7X0ZW8KiYz0jyAgNaeSJ1rCfDI= github.com/docker/machine v0.16.1/go.mod h1:I8mPNDeK1uH+JTcUU7X0ZW8KiYz0jyAgNaeSJ1rCfDI=
github.com/fsnotify/fsnotify v0.0.0-20160816051541-f12c6236fe7b h1:lHoxUxMozh/yCASOoFep9dPMva62ztmxKK2VB8//Aoo= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fsnotify/fsnotify v0.0.0-20160816051541-f12c6236fe7b/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
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 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 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 h1:ago6fNuQ6IhszPsXkeU7qRCyfsIX7L67WDybsAPkLl8=
@ -29,7 +36,6 @@ github.com/golang/glog v0.0.0-20141105023935-44145f04b68c h1:CbdkBQ1/PiAo0FYJhQG
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/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 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 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/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 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
@ -46,6 +52,8 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 h1:ScAXWS+TR6MZKex+7
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= 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/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4=
@ -58,8 +66,12 @@ github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 h1:OaRuzt9oCK
github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 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/hcl v0.0.0-20160711231752-d8c773c4cba1 h1:9j16AiR0R5hDbDBMzfUfIP9CUbbw6T8nYN4iZz3/wjg=
github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
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 h1:ARl0RuGZTqBOMXQIfXen0twVSJ8kMojd7ThJf4EBcrc=
github.com/hooklift/iso9660 v0.0.0-20170318115843-1cf07e5970d8/go.mod h1:sOC47ru8lB0DlU0EZ7BJ0KCP5rDqOvx0c/5K5ADm8H0= 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 h1:FeeCi0I2Fu8kA8IXrdVPtGzym+mW9bzfj9f26EaES9k=
github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
@ -72,16 +84,25 @@ github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345 h1:XP1
github.com/johanneswuerbach/nfsexports v0.0.0-20181204082207-1aa528dcb345/go.mod h1:+c1/kUpg2zlkoWqTOvzDs36Wpbm3Gd1nlmtXAEB0WGU= 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 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
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 h1:YUrU1/jxRqnt0PSrKj1Uj/wEjk/fjnE80QFfi2Zlj7Q=
github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169/go.mod h1:glhvuHOU9Hy7/8PwwdtnarXqLagOX0b/TbZx2zLMqEg= 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.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/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/libvirt/libvirt-go v3.4.0+incompatible h1:Cpyalgj1x8JIeTlL6SDYZBo7j8nY3+5XHqmi8DaunCk= 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/libvirt/libvirt-go v3.4.0+incompatible/go.mod h1:34zsnB4iGeOv7Byj6qotuW8Ya4v4Tr43ttjz/F0wjLE=
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 h1:+E1IKKk+6kaQrCPg6edJZ/zISZijuZTPnzy6RE4C/Ho=
github.com/machine-drivers/docker-machine-driver-vmware v0.1.1/go.mod h1:ej014C83EmSnxJeJ8PtVb8OLJ91PJKO1Q8Y7sM5CK0o= 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 h1:YVH4JcnWs1z/qQ2Dg5BnGGQL8PcUOO97Sb5w7RyuBl4=
github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
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 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.0-20161012013512-737072b4e32b/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 h1:kw1v0NlnN+GZcU8Ma8CLF2Zzgjfx95gs3/GN3vYAPpo= github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 h1:kw1v0NlnN+GZcU8Ma8CLF2Zzgjfx95gs3/GN3vYAPpo=
@ -96,13 +117,17 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/olekukonko/tablewriter v0.0.0-20160923125401-bdcc175572fd h1:nEatQ6JnwCT9iYD5uqYUiFqq8tJGX25to8KVKXqya7k= 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/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 v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca h1:dKRMHfduZ/ZqOHuYGk/0kkTIUbnyorkAfzLOp6Ts8pU= 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/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 h1:ig6N9Cg71k/P+UUbhwdOFtJWz+qa8/3by7AzMprMWBM=
github.com/pelletier/go-buffruneio v0.1.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= 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 h1:tMVXZ04h5CqgTvMyA8IL1b9xlJz7G+mTcCsYi3WXRtA=
github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v0.0.0-20160822122712-0049ab3dc4c4/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/browser v0.0.0-20160118053552-9302be274faa h1:od00Tr1U7+cLVtc+RNFmR53spHUF98Ziu33S8UIQnt0= github.com/pkg/browser v0.0.0-20160118053552-9302be274faa h1:od00Tr1U7+cLVtc+RNFmR53spHUF98Ziu33S8UIQnt0=
@ -123,8 +148,8 @@ github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859 h1:XRl74t6xHK
github.com/samalba/dockerclient v0.0.0-20160414174713-91d7393ff859/go.mod h1:yeYR4SlaRZJct6lwNRKR+qd0CocnxxWDE7Vh5dxsn/w= 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/shurcooL/sanitized_anchor_name v0.0.0-20151028001915-10ef21a441db h1:lrOUn8raSZS/V52c7elGaEyuogqSkEo/Qj2Auo2G1ik=
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-20151028001915-10ef21a441db/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2 h1:+8J/sCAVv2Y9Ct1BKszDFJEVWv6Aynr2O4FYGUg6+Mc= github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v0.0.0-20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= 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/spf13/afero v0.0.0-20160816080757-b28a7effac97 h1:Gv1HykSEG+RKWWWkM69nPrJKhE/EM2oFb1nBWogHNv8=
github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 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/cast v0.0.0-20160730092037-e31f36ffc91a h1:tPI5RnYZJhcXj0LhJ9pi7PS7gqOhuFR+4HEKyDz3BnQ=
@ -137,6 +162,12 @@ github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I=
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= 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/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/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 h1:KM4T3G70MiR+JtqplcYkNVoNz7pDwYaBxWBXQK804So= 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/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 h1:XZWnr3bsDQWAZg4Ne+cPoXRPILrNlPNQfxBuwLl43is=
@ -145,12 +176,10 @@ github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be h1:sRGd3e18iz
github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v0.0.0-20160623135812-c539bca196be/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 h1:Ucx5I1l1+TWXvqFmBigYu4Ub4MLvUuUU/whjoUvV95I= 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= github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097/go.mod h1:lFZSWRIpCfE/pt91hHBBpV6+x87YlCjsp+aIR2qCPPU=
golang.org/x/crypto v0.0.0-20170825220121-81e90905daef h1:R8ubLIilYRXIXpgjOg2l/ECVs3HzVKIjJEhxSsQ91u4=
golang.org/x/crypto v0.0.0-20170825220121-81e90905daef/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20170809000501-1c05540f6879/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
@ -158,15 +187,17 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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 h1:pcBdqVcrlT+A3i+tWsOROFONQyey9tisIQHI4xqVGLg=
golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190115181402-5dab4167f31c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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 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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20171031081856-95c657629925 h1:nCH33NboKIsT4HoXBsXTWX8ul303HxWgkc5s2Ezwacg= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20171031081856-95c657629925/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-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 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/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -174,13 +205,27 @@ golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wk
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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/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 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.6/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/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 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054 h1:ROF+R/wHHruzF40n5DfPv2jwm7rCJwvs8fz+RTZWjLE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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/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 h1:hROmpFC7JMobXFXMmD7ZKZLhDKvr1IKfFJoYS/45G/8=
k8s.io/api v0.0.0-20180712090710-2d6f90ab1293/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= 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 h1:MZjlsu9igBoVPZkXpIGoxI6EonqNsXXZU7hhvfQLkd4=

View File

@ -25,9 +25,15 @@ import (
) )
func main() { func main() {
os.MkdirAll("./out/docs", os.FileMode(0755)) if err := os.MkdirAll("./out/docs", os.FileMode(0755)); err != nil {
fmt.Println(err)
os.Exit(1)
}
cmd.RootCmd.DisableAutoGenTag = true cmd.RootCmd.DisableAutoGenTag = true
doc.GenMarkdownTree(cmd.RootCmd, "./out/docs") if err := doc.GenMarkdownTree(cmd.RootCmd, "./out/docs"); err != nil {
fmt.Println(err)
os.Exit(1)
}
f, err := os.Create("./out/docs/bash-completion") f, err := os.Create("./out/docs/bash-completion")
if err != nil { if err != nil {

View File

@ -23,6 +23,8 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"github.com/golang/glog"
) )
func main() { func main() {
@ -56,21 +58,29 @@ func main() {
re = regexp.MustCompile(`var NewestKubernetesVersion = .*`) re = regexp.MustCompile(`var NewestKubernetesVersion = .*`)
f = re.ReplaceAllString(f, "var NewestKubernetesVersion = \""+v+"\"") f = re.ReplaceAllString(f, "var NewestKubernetesVersion = \""+v+"\"")
ioutil.WriteFile(constantsFile, []byte(f), mode) if err := ioutil.WriteFile(constantsFile, []byte(f), mode); err != nil {
fmt.Println(err)
os.Exit(1)
}
testData := "../../pkg/minikube/bootstrapper/kubeadm/testdata" testData := "../../pkg/minikube/bootstrapper/kubeadm/testdata"
err = filepath.Walk(testData, func(path string, info os.FileInfo, err error) error { err = filepath.Walk(testData, func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(path, "default.yaml") { if err != nil {
return err
}
if !strings.HasSuffix(path, "default.yaml") {
return nil
}
cf, err = ioutil.ReadFile(path) cf, err = ioutil.ReadFile(path)
if err != nil { if err != nil {
// Keep going if this errors out return err
fmt.Println(err)
} }
re = regexp.MustCompile(`kubernetesVersion: .*`) re = regexp.MustCompile(`kubernetesVersion: .*`)
cf = []byte(re.ReplaceAllString(string(cf), "kubernetesVersion: "+v)) cf = []byte(re.ReplaceAllString(string(cf), "kubernetesVersion: "+v))
ioutil.WriteFile(path, cf, info.Mode()) return ioutil.WriteFile(path, cf, info.Mode())
}
return nil
}) })
if err != nil {
glog.Errorf("Walk failed: %v", err)
}
} }

View File

@ -97,7 +97,7 @@ func printPullRequests() {
} }
func getClient() *github.Client { func getClient() *github.Client {
if len(token) <= 0 { if len(token) == 0 {
return github.NewClient(nil) return github.NewClient(nil)
} }
ctx := context.Background() ctx := context.Background()

View File

@ -17,6 +17,7 @@ limitations under the License.
package drivers package drivers
import ( import (
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -51,25 +52,27 @@ func (d *CommonDriver) SetConfigFromFlags(flags drivers.DriverOptions) error {
func createRawDiskImage(sshKeyPath, diskPath string, diskSizeMb int) error { func createRawDiskImage(sshKeyPath, diskPath string, diskSizeMb int) error {
tarBuf, err := mcnutils.MakeDiskImage(sshKeyPath) tarBuf, err := mcnutils.MakeDiskImage(sshKeyPath)
if err != nil { if err != nil {
return err return errors.Wrap(err, "make disk image")
} }
file, err := os.OpenFile(diskPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) file, err := os.OpenFile(diskPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
if err != nil { if err != nil {
return err return errors.Wrap(err, "open")
} }
defer file.Close() defer file.Close()
file.Seek(0, os.SEEK_SET) if _, err := file.Seek(0, io.SeekStart); err != nil {
return errors.Wrap(err, "seek")
}
if _, err := file.Write(tarBuf.Bytes()); err != nil { if _, err := file.Write(tarBuf.Bytes()); err != nil {
return err return errors.Wrap(err, "write tar")
} }
if err := file.Close(); err != nil { if err := file.Close(); err != nil {
return errors.Wrapf(err, "closing file %s", diskPath) return errors.Wrapf(err, "closing file %s", diskPath)
} }
if err := os.Truncate(diskPath, int64(diskSizeMb*1000000)); err != nil { if err := os.Truncate(diskPath, int64(diskSizeMb*1000000)); err != nil {
return err return errors.Wrap(err, "truncate")
} }
return nil return nil
} }
@ -91,37 +94,45 @@ func Restart(d drivers.Driver) error {
// MakeDiskImage makes a boot2docker VM disk image. // MakeDiskImage makes a boot2docker VM disk image.
func MakeDiskImage(d *drivers.BaseDriver, boot2dockerURL string, diskSize int) error { func MakeDiskImage(d *drivers.BaseDriver, boot2dockerURL string, diskSize int) error {
//TODO(r2d4): rewrite this, not using b2dutils glog.Infof("Making disk image using store path: %s", d.StorePath)
b2dutils := mcnutils.NewB2dUtils(d.StorePath) b2 := mcnutils.NewB2dUtils(d.StorePath)
if err := b2dutils.CopyIsoToMachineDir(boot2dockerURL, d.MachineName); err != nil { if err := b2.CopyIsoToMachineDir(boot2dockerURL, d.MachineName); err != nil {
return errors.Wrap(err, "Error copying ISO to machine dir") return errors.Wrap(err, "copy iso to machine dir")
} }
glog.Info("Creating ssh key...") keyPath := d.GetSSHKeyPath()
if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { glog.Infof("Creating ssh key: %s...", keyPath)
return err if err := ssh.GenerateSSHKey(keyPath); err != nil {
return errors.Wrap(err, "generate ssh key")
} }
glog.Info("Creating raw disk image...")
diskPath := GetDiskPath(d) diskPath := GetDiskPath(d)
glog.Infof("Creating raw disk image: %s...", diskPath)
if _, err := os.Stat(diskPath); os.IsNotExist(err) { if _, err := os.Stat(diskPath); os.IsNotExist(err) {
if err := createRawDiskImage(publicSSHKeyPath(d), diskPath, diskSize); err != nil { if err := createRawDiskImage(publicSSHKeyPath(d), diskPath, diskSize); err != nil {
return err return errors.Wrapf(err, "createRawDiskImage(%s)", diskPath)
} }
if err := fixPermissions(d.ResolveStorePath(".")); err != nil { machPath := d.ResolveStorePath(".")
return err if err := fixPermissions(machPath); err != nil {
return errors.Wrapf(err, "fixing permissions on %s", machPath)
} }
} }
return nil return nil
} }
func fixPermissions(path string) error { func fixPermissions(path string) error {
os.Chown(path, syscall.Getuid(), syscall.Getegid()) glog.Infof("Fixing permissions on %s ...", path)
files, _ := ioutil.ReadDir(path) if err := os.Chown(path, syscall.Getuid(), syscall.Getegid()); err != nil {
return errors.Wrap(err, "chown dir")
}
files, err := ioutil.ReadDir(path)
if err != nil {
return errors.Wrap(err, "read dir")
}
for _, f := range files { for _, f := range files {
fp := filepath.Join(path, f.Name()) fp := filepath.Join(path, f.Name())
if err := os.Chown(fp, syscall.Getuid(), syscall.Getegid()); err != nil { if err := os.Chown(fp, syscall.Getuid(), syscall.Getegid()); err != nil {
return err return errors.Wrap(err, "chown file")
} }
} }
return nil return nil

View File

@ -30,7 +30,9 @@ func Test_createDiskImage(t *testing.T) {
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
sshPath := filepath.Join(tmpdir, "ssh") sshPath := filepath.Join(tmpdir, "ssh")
ioutil.WriteFile(sshPath, []byte("mysshkey"), 0644) if err := ioutil.WriteFile(sshPath, []byte("mysshkey"), 0644); err != nil {
t.Fatalf("writefile: %v", err)
}
diskPath := filepath.Join(tmpdir, "disk") diskPath := filepath.Join(tmpdir, "disk")
sizeInMb := 100 sizeInMb := 100

View File

@ -36,10 +36,11 @@ import (
"github.com/docker/machine/libmachine/log" "github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/state" "github.com/docker/machine/libmachine/state"
"github.com/johanneswuerbach/nfsexports" "github.com/johanneswuerbach/nfsexports"
"github.com/mitchellh/go-ps" ps "github.com/mitchellh/go-ps"
"github.com/moby/hyperkit/go" hyperkit "github.com/moby/hyperkit/go"
"github.com/pkg/errors" "github.com/pkg/errors"
pkgdrivers "k8s.io/minikube/pkg/drivers" pkgdrivers "k8s.io/minikube/pkg/drivers"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
commonutil "k8s.io/minikube/pkg/util" commonutil "k8s.io/minikube/pkg/util"
) )

View File

@ -19,7 +19,6 @@ package hyperkit
import ( import (
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"strings" "strings"
@ -29,10 +28,10 @@ import (
// ExtractFile extracts a file from an ISO // ExtractFile extracts a file from an ISO
func ExtractFile(isoPath, srcPath, destPath string) error { func ExtractFile(isoPath, srcPath, destPath string) error {
iso, err := os.Open(isoPath) iso, err := os.Open(isoPath)
defer iso.Close()
if err != nil { if err != nil {
return err return err
} }
defer iso.Close()
r, err := iso9660.NewReader(iso) r, err := iso9660.NewReader(iso)
if err != nil { if err != nil {
@ -45,36 +44,15 @@ func ExtractFile(isoPath, srcPath, destPath string) error {
} }
dst, err := os.Create(destPath) dst, err := os.Create(destPath)
defer dst.Close()
if err != nil { if err != nil {
return err return err
} }
defer dst.Close()
_, err = io.Copy(dst, f.Sys().(io.Reader)) _, err = io.Copy(dst, f.Sys().(io.Reader))
return err return err
} }
func readFile(isoPath, srcPath string) (string, error) {
iso, err := os.Open(isoPath)
defer iso.Close()
if err != nil {
return "", err
}
r, err := iso9660.NewReader(iso)
if err != nil {
return "", err
}
f, err := findFile(r, srcPath)
if err != nil {
return "", err
}
contents, err := ioutil.ReadAll(f.Sys().(io.Reader))
return string(contents), err
}
func findFile(r *iso9660.Reader, path string) (os.FileInfo, error) { func findFile(r *iso9660.Reader, path string) (os.FileInfo, error) {
// Look through the ISO for a file with a matching path. // Look through the ISO for a file with a matching path.
for f, err := r.Next(); err != io.EOF; f, err = r.Next() { for f, err := r.Next(); err != io.EOF; f, err = r.Next() {

View File

@ -1,3 +1,5 @@
// +build darwin
/* /*
Copyright 2016 The Kubernetes Authors All rights reserved. Copyright 2016 The Kubernetes Authors All rights reserved.
@ -38,6 +40,10 @@ const (
SharedNetAddrKey = "Shared_Net_Address" SharedNetAddrKey = "Shared_Net_Address"
) )
var (
leadingZeroRegexp = regexp.MustCompile(`0([A-Fa-f0-9](:|$))`)
)
// DHCPEntry holds a parsed DNS entry // DHCPEntry holds a parsed DNS entry
type DHCPEntry struct { type DHCPEntry struct {
Name string Name string
@ -118,10 +124,7 @@ func parseDHCPdLeasesFile(file io.Reader) ([]DHCPEntry, error) {
// trimMacAddress trimming "0" of the ten's digit // trimMacAddress trimming "0" of the ten's digit
func trimMacAddress(rawUUID string) string { func trimMacAddress(rawUUID string) string {
re := regexp.MustCompile(`0([A-Fa-f0-9](:|$))`) return leadingZeroRegexp.ReplaceAllString(rawUUID, "$1")
mac := re.ReplaceAllString(rawUUID, "$1")
return mac
} }
// GetNetAddr gets the network address for vmnet // GetNetAddr gets the network address for vmnet

View File

@ -1,3 +1,5 @@
// +build darwin
/* /*
Copyright 2016 The Kubernetes Authors All rights reserved. Copyright 2016 The Kubernetes Authors All rights reserved.
@ -52,10 +54,14 @@ func Test_getIpAddressFromFile(t *testing.T) {
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
dhcpFile := filepath.Join(tmpdir, "dhcp") dhcpFile := filepath.Join(tmpdir, "dhcp")
ioutil.WriteFile(dhcpFile, validLeases, 0644) if err := ioutil.WriteFile(dhcpFile, validLeases, 0644); err != nil {
t.Fatalf("writefile: %v", err)
}
invalidFile := filepath.Join(tmpdir, "invalid") invalidFile := filepath.Join(tmpdir, "invalid")
ioutil.WriteFile(invalidFile, []byte("foo"), 0644) if err := ioutil.WriteFile(invalidFile, []byte("foo"), 0644); err != nil {
t.Fatalf("writefile: %v", err)
}
type args struct { type args struct {
mac string mac string

View File

@ -22,6 +22,6 @@ import (
vmnet "github.com/zchee/go-vmnet" vmnet "github.com/zchee/go-vmnet"
) )
func GetMACAddressFromUUID(UUID string) (string, error) { func GetMACAddressFromUUID(id string) (string, error) {
return vmnet.GetMACAddressFromUUID(UUID) return vmnet.GetMACAddressFromUUID(id)
} }

View File

@ -1,3 +1,5 @@
// +build linux
/* /*
Copyright 2016 The Kubernetes Authors All rights reserved. Copyright 2016 The Kubernetes Authors All rights reserved.
@ -121,7 +123,7 @@ func randomMAC() (net.HardwareAddr, error) {
// The second LSB of the first octet // The second LSB of the first octet
// 0 for universally administered addresses // 0 for universally administered addresses
// 1 for locally administered addresses // 1 for locally administered addresses
buf[0] = buf[0] & 0xfc buf[0] &= 0xfc
return buf, nil return buf, nil
} }
@ -149,11 +151,14 @@ func getConnection() (*libvirt.Connect, error) {
} }
func closeDomain(dom *libvirt.Domain, conn *libvirt.Connect) error { func closeDomain(dom *libvirt.Domain, conn *libvirt.Connect) error {
dom.Free() if err := dom.Free(); err != nil {
if res, _ := conn.Close(); res != 0 { return err
return fmt.Errorf("Error closing connection CloseConnection() == %d, expected 0", res)
} }
return nil res, err := conn.Close()
if res != 0 {
return fmt.Errorf("CloseConnection() == %d, expected 0", res)
}
return err
} }
func (d *Driver) createDomain() (*libvirt.Domain, error) { func (d *Driver) createDomain() (*libvirt.Domain, error) {

View File

@ -1,3 +1,5 @@
// +build linux
/* /*
Copyright 2018 The Kubernetes Authors All rights reserved. Copyright 2018 The Kubernetes Authors All rights reserved.

View File

@ -1,3 +1,5 @@
// +build linux
/* /*
Copyright 2016 The Kubernetes Authors All rights reserved. Copyright 2016 The Kubernetes Authors All rights reserved.
@ -20,6 +22,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"syscall"
"time" "time"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
@ -140,18 +143,27 @@ func (d *Driver) GetURL() (string, error) {
} }
// GetState returns the state that the host is in (running, stopped, etc) // GetState returns the state that the host is in (running, stopped, etc)
func (d *Driver) GetState() (state.State, error) { func (d *Driver) GetState() (st state.State, err error) {
dom, conn, err := d.getDomain() dom, conn, err := d.getDomain()
if err != nil { if err != nil {
return state.None, errors.Wrap(err, "getting connection") return state.None, errors.Wrap(err, "getting connection")
} }
defer closeDomain(dom, conn) defer func() {
if ferr := closeDomain(dom, conn); ferr != nil {
err = ferr
}
}()
libvirtState, _, err := dom.GetState() // state, reason, error lvs, _, err := dom.GetState() // state, reason, error
if err != nil { if err != nil {
return state.None, errors.Wrap(err, "getting domain state") return state.None, errors.Wrap(err, "getting domain state")
} }
st = machineState(lvs)
return // st, err
}
// machineState converts libvirt state to libmachine state
func machineState(lvs libvirt.DomainState) state.State {
// Possible States: // Possible States:
// //
// VIR_DOMAIN_NOSTATE no state // VIR_DOMAIN_NOSTATE no state
@ -164,23 +176,23 @@ func (d *Driver) GetState() (state.State, error) {
// VIR_DOMAIN_PMSUSPENDED the domain is suspended by guest power management // VIR_DOMAIN_PMSUSPENDED the domain is suspended by guest power management
// VIR_DOMAIN_LAST this enum value will increase over time as new events are added to the libvirt API. It reflects the last state supported by this version of the libvirt API. // VIR_DOMAIN_LAST this enum value will increase over time as new events are added to the libvirt API. It reflects the last state supported by this version of the libvirt API.
switch libvirtState { switch lvs {
// DOMAIN_SHUTDOWN technically means the VM is still running, but in the // DOMAIN_SHUTDOWN technically means the VM is still running, but in the
// process of being shutdown, so we return state.Running // process of being shutdown, so we return state.Running
case libvirt.DOMAIN_RUNNING, libvirt.DOMAIN_SHUTDOWN: case libvirt.DOMAIN_RUNNING, libvirt.DOMAIN_SHUTDOWN:
return state.Running, nil return state.Running
case libvirt.DOMAIN_BLOCKED, libvirt.DOMAIN_CRASHED: case libvirt.DOMAIN_BLOCKED, libvirt.DOMAIN_CRASHED:
return state.Error, nil return state.Error
case libvirt.DOMAIN_PAUSED: case libvirt.DOMAIN_PAUSED:
return state.Paused, nil return state.Paused
case libvirt.DOMAIN_SHUTOFF: case libvirt.DOMAIN_SHUTOFF:
return state.Stopped, nil return state.Stopped
case libvirt.DOMAIN_PMSUSPENDED: case libvirt.DOMAIN_PMSUSPENDED:
return state.Saved, nil return state.Saved
case libvirt.DOMAIN_NOSTATE: case libvirt.DOMAIN_NOSTATE:
return state.None, nil return state.None
default: default:
return state.None, nil return state.None
} }
} }
@ -212,13 +224,16 @@ func (d *Driver) DriverName() string {
} }
// Kill stops a host forcefully, including any containers that we are managing. // Kill stops a host forcefully, including any containers that we are managing.
func (d *Driver) Kill() error { func (d *Driver) Kill() (err error) {
dom, conn, err := d.getDomain() dom, conn, err := d.getDomain()
if err != nil { if err != nil {
return errors.Wrap(err, "getting connection") return errors.Wrap(err, "getting connection")
} }
defer closeDomain(dom, conn) defer func() {
if ferr := closeDomain(dom, conn); ferr != nil {
err = ferr
}
}()
return dom.Destroy() return dom.Destroy()
} }
@ -228,11 +243,11 @@ func (d *Driver) Restart() error {
} }
// Start a host // Start a host
func (d *Driver) Start() error { func (d *Driver) Start() (err error) {
// if somebody/something deleted the network in the meantime, // if somebody/something deleted the network in the meantime,
// we might need to recreate it. It's (nearly) a noop if the network exists. // we might need to recreate it. It's (nearly) a noop if the network exists.
log.Info("Creating network...") log.Info("Creating network...")
err := d.createNetwork() err = d.createNetwork()
if err != nil { if err != nil {
return errors.Wrap(err, "creating network") return errors.Wrap(err, "creating network")
} }
@ -249,7 +264,11 @@ func (d *Driver) Start() error {
if err != nil { if err != nil {
return errors.Wrap(err, "getting connection") return errors.Wrap(err, "getting connection")
} }
defer closeDomain(dom, conn) defer func() {
if ferr := closeDomain(dom, conn); ferr != nil {
err = ferr
}
}()
log.Info("Creating domain...") log.Info("Creating domain...")
if err := dom.Create(); err != nil { if err := dom.Create(); err != nil {
@ -289,10 +308,11 @@ func (d *Driver) Start() error {
} }
// Create a host using the driver's config // Create a host using the driver's config
func (d *Driver) Create() error { func (d *Driver) Create() (err error) {
log.Info("Creating machine...") log.Info("Creating KVM machine...")
log.Info("Creating network...") defer log.Infof("KVM machine creation complete!")
err := d.createNetwork()
err = d.createNetwork()
if err != nil { if err != nil {
return errors.Wrap(err, "creating network") return errors.Wrap(err, "creating network")
} }
@ -304,42 +324,64 @@ func (d *Driver) Create() error {
} }
} }
log.Info("Setting up minikube home directory...") store := d.ResolveStorePath(".")
if err := os.MkdirAll(d.ResolveStorePath("."), 0755); err != nil { log.Infof("Setting up store path in %s ...", store)
return errors.Wrap(err, "Error making store path directory") // 0755 because it must be accessible by libvirt/qemu across a variety of configs
if err := os.MkdirAll(store, 0755); err != nil {
return errors.Wrap(err, "creating store")
} }
for dir := d.ResolveStorePath("."); dir != "/"; dir = filepath.Dir(dir) { log.Infof("Building disk image from %s", d.Boot2DockerURL)
info, err := os.Stat(dir)
if err != nil {
return err
}
mode := info.Mode()
if mode&0011 != 1 {
log.Debugf("Setting executable bit set on %s", dir)
mode |= 0011
os.Chmod(dir, mode)
}
}
log.Info("Building disk image...")
if err = pkgdrivers.MakeDiskImage(d.BaseDriver, d.Boot2DockerURL, d.DiskSize); err != nil { if err = pkgdrivers.MakeDiskImage(d.BaseDriver, d.Boot2DockerURL, d.DiskSize); err != nil {
return errors.Wrap(err, "Error creating disk") return errors.Wrap(err, "Error creating disk")
} }
if err := ensureDirPermissions(store); err != nil {
log.Errorf("unable to ensure permissions on %s: %v", store, err)
}
log.Info("Creating domain...") log.Info("Creating domain...")
dom, err := d.createDomain() dom, err := d.createDomain()
if err != nil { if err != nil {
return errors.Wrap(err, "creating domain") return errors.Wrap(err, "creating domain")
} }
defer dom.Free() defer func() {
if ferr := dom.Free(); ferr != nil {
log.Debug("Finished creating machine, now starting machine...") err = ferr
}
}()
return d.Start() return d.Start()
} }
// ensureDirPermissions ensures that libvirt has access to access the image store directory
func ensureDirPermissions(store string) error {
// traverse upwards from /home/user/.minikube/machines to ensure
// that libvirt/qemu has execute access
for dir := store; dir != "/"; dir = filepath.Dir(dir) {
log.Debugf("Checking permissions on dir: %s", dir)
s, err := os.Stat(dir)
if err != nil {
return err
}
owner := int(s.Sys().(*syscall.Stat_t).Uid)
if owner != os.Geteuid() {
log.Debugf("Skipping %s - not owner", dir)
continue
}
mode := s.Mode()
if mode&0011 != 1 {
log.Infof("Setting executable bit set on %s (perms=%s)", dir, mode)
mode |= 0011
if err := os.Chmod(dir, mode); err != nil {
return err
}
}
}
return nil
}
// Stop a host gracefully // Stop a host gracefully
func (d *Driver) Stop() error { func (d *Driver) Stop() (err error) {
d.IPAddress = "" d.IPAddress = ""
s, err := d.GetState() s, err := d.GetState()
if err != nil { if err != nil {
@ -348,7 +390,11 @@ func (d *Driver) Stop() error {
if s != state.Stopped { if s != state.Stopped {
dom, conn, err := d.getDomain() dom, conn, err := d.getDomain()
defer closeDomain(dom, conn) defer func() {
if ferr := closeDomain(dom, conn); ferr != nil {
err = ferr
}
}()
if err != nil { if err != nil {
return errors.Wrap(err, "getting connection") return errors.Wrap(err, "getting connection")
} }
@ -372,7 +418,7 @@ func (d *Driver) Stop() error {
} }
return fmt.Errorf("Could not stop VM, current state %s", s.String()) return fmt.Errorf("unable to stop vm, current state %q", s.String())
} }
// Remove a host // Remove a host
@ -400,8 +446,12 @@ func (d *Driver) Remove() error {
} }
if dom != nil { if dom != nil {
log.Infof("Domain %s exists, removing...", d.MachineName) log.Infof("Domain %s exists, removing...", d.MachineName)
dom.Destroy() if err := dom.Destroy(); err != nil {
dom.Undefine() return err
}
if err := dom.Undefine(); err != nil {
return err
}
} }
return nil return nil

View File

@ -1,3 +1,5 @@
// +build linux
/* /*
Copyright 2016 The Kubernetes Authors All rights reserved. Copyright 2016 The Kubernetes Authors All rights reserved.
@ -320,7 +322,7 @@ func (d *Driver) lookupIPFromLeasesFile() (string, error) {
// ExpiryTime MAC IP Hostname ExtendedMAC // ExpiryTime MAC IP Hostname ExtendedMAC
entry := strings.Split(lease, " ") entry := strings.Split(lease, " ")
if len(entry) != 5 { if len(entry) != 5 {
return "", fmt.Errorf("Malformed leases entry: %s", entry) return "", fmt.Errorf("malformed leases entry: %s", entry)
} }
if entry[1] == d.PrivateMAC { if entry[1] == d.PrivateMAC {
ipAddress = entry[2] ipAddress = entry[2]

View File

@ -341,7 +341,10 @@ func AddMinikubeDirAssets(assets *[]CopyableFile) error {
// of files to be copied to the vm. If vmpath is left blank, the files will be // of files to be copied to the vm. If vmpath is left blank, the files will be
// transferred to the location according to their relative minikube folder path. // transferred to the location according to their relative minikube folder path.
func addMinikubeDirToAssets(basedir, vmpath string, assets *[]CopyableFile) error { func addMinikubeDirToAssets(basedir, vmpath string, assets *[]CopyableFile) error {
err := filepath.Walk(basedir, func(hostpath string, info os.FileInfo, err error) error { return filepath.Walk(basedir, func(hostpath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
isDir, err := util.IsDirectory(hostpath) isDir, err := util.IsDirectory(hostpath)
if err != nil { if err != nil {
return errors.Wrapf(err, "checking if %s is directory", hostpath) return errors.Wrapf(err, "checking if %s is directory", hostpath)
@ -373,10 +376,6 @@ func addMinikubeDirToAssets(basedir, vmpath string, assets *[]CopyableFile) erro
return nil return nil
}) })
if err != nil {
return errors.Wrap(err, "walking filepath")
}
return nil
} }
// GenerateTemplateData generates template data for template assets // GenerateTemplateData generates template data for template assets

View File

@ -41,12 +41,11 @@ func TestAddMinikubeDirAssets(t *testing.T) {
tests := []struct { tests := []struct {
description string description string
baseDir string baseDir string
vmPath string
files []struct { files []struct {
relativePath string relativePath string
expectedPath string expectedPath string
} }
vmPath string
expectedCfg string
}{ }{
{ {
description: "relative path assets", description: "relative path assets",
@ -113,7 +112,7 @@ func TestAddMinikubeDirAssets(t *testing.T) {
testDirs = append(testDirs, testDir) testDirs = append(testDirs, testDir)
testFileBaseDir := filepath.Join(testDir, test.baseDir) testFileBaseDir := filepath.Join(testDir, test.baseDir)
want := make(map[string]string, 0) want := make(map[string]string)
for _, fileDef := range test.files { for _, fileDef := range test.files {
err := func() error { err := func() error {
path := filepath.Join(testFileBaseDir, fileDef.relativePath) path := filepath.Join(testFileBaseDir, fileDef.relativePath)
@ -146,7 +145,7 @@ func TestAddMinikubeDirAssets(t *testing.T) {
return return
} }
got := make(map[string]string, 0) got := make(map[string]string)
for _, actualFile := range actualFiles { for _, actualFile := range actualFiles {
got[actualFile.GetAssetName()] = actualFile.GetTargetDir() got[actualFile.GetAssetName()] = actualFile.GetTargetDir()
} }

View File

@ -40,9 +40,6 @@ type CopyableFile interface {
// BaseAsset is the base asset class // BaseAsset is the base asset class
type BaseAsset struct { type BaseAsset struct {
data []byte
reader io.Reader
Length int
AssetName string AssetName string
TargetDir string TargetDir string
TargetName string TargetName string
@ -72,6 +69,7 @@ func (b *BaseAsset) GetPermissions() string {
// FileAsset is an asset using a file // FileAsset is an asset using a file
type FileAsset struct { type FileAsset struct {
BaseAsset BaseAsset
reader io.Reader
} }
// NewMemoryAssetTarget creates a new MemoryAsset, with target // NewMemoryAssetTarget creates a new MemoryAsset, with target
@ -80,31 +78,25 @@ func NewMemoryAssetTarget(d []byte, targetPath, permissions string) *MemoryAsset
} }
// NewFileAsset creates a new FileAsset // NewFileAsset creates a new FileAsset
func NewFileAsset(assetName, targetDir, targetName, permissions string) (*FileAsset, error) { func NewFileAsset(path, targetDir, targetName, permissions string) (*FileAsset, error) {
f := &FileAsset{ f, err := os.Open(path)
BaseAsset{ if err != nil {
AssetName: assetName, return nil, errors.Wrapf(err, "Error opening file asset: %s", path)
}
return &FileAsset{
BaseAsset: BaseAsset{
AssetName: path,
TargetDir: targetDir, TargetDir: targetDir,
TargetName: targetName, TargetName: targetName,
Permissions: permissions, Permissions: permissions,
}, },
} reader: f,
file, err := os.Open(f.AssetName) }, nil
if err != nil {
return nil, errors.Wrapf(err, "Error opening file asset: %s", f.AssetName)
}
f.reader = file
return f, nil
} }
// GetLength returns the file length, or 0 (on error) // GetLength returns the file length, or 0 (on error)
func (f *FileAsset) GetLength() int { func (f *FileAsset) GetLength() (flen int) {
file, err := os.Open(f.AssetName) fi, err := os.Stat(f.AssetName)
defer file.Close()
if err != nil {
return 0
}
fi, err := file.Stat()
if err != nil { if err != nil {
return 0 return 0
} }
@ -121,11 +113,13 @@ func (f *FileAsset) Read(p []byte) (int, error) {
// MemoryAsset is a memory-based asset // MemoryAsset is a memory-based asset
type MemoryAsset struct { type MemoryAsset struct {
BaseAsset BaseAsset
reader io.Reader
length int
} }
// GetLength returns length // GetLength returns length
func (m *MemoryAsset) GetLength() int { func (m *MemoryAsset) GetLength() int {
return m.Length return m.length
} }
// Read reads the asset // Read reads the asset
@ -135,24 +129,23 @@ func (m *MemoryAsset) Read(p []byte) (int, error) {
// NewMemoryAsset creates a new MemoryAsset // NewMemoryAsset creates a new MemoryAsset
func NewMemoryAsset(d []byte, targetDir, targetName, permissions string) *MemoryAsset { func NewMemoryAsset(d []byte, targetDir, targetName, permissions string) *MemoryAsset {
m := &MemoryAsset{ return &MemoryAsset{
BaseAsset{ BaseAsset: BaseAsset{
TargetDir: targetDir, TargetDir: targetDir,
TargetName: targetName, TargetName: targetName,
Permissions: permissions, Permissions: permissions,
}, },
reader: bytes.NewReader(d),
length: len(d),
} }
m.data = d
m.Length = len(m.data)
m.reader = bytes.NewReader(m.data)
return m
} }
// BinAsset is a bindata (binary data) asset // BinAsset is a bindata (binary data) asset
type BinAsset struct { type BinAsset struct {
BaseAsset BaseAsset
reader io.Reader
template *template.Template template *template.Template
length int
} }
// MustBinAsset creates a new BinAsset, or panics if invalid // MustBinAsset creates a new BinAsset, or panics if invalid
@ -205,11 +198,10 @@ func (m *BinAsset) loadData(isTemplate bool) error {
m.template = tpl m.template = tpl
} }
m.data = contents m.length = len(contents)
m.Length = len(contents) m.reader = bytes.NewReader(contents)
m.reader = bytes.NewReader(m.data) glog.Infof("Created asset %s with %d bytes", m.AssetName, m.length)
glog.Infof("Created asset %s with %d bytes", m.AssetName, m.Length) if m.length == 0 {
if m.Length == 0 {
return fmt.Errorf("%s is an empty asset", m.AssetName) return fmt.Errorf("%s is an empty asset", m.AssetName)
} }
return nil return nil
@ -237,12 +229,12 @@ func (m *BinAsset) Evaluate(data interface{}) (*MemoryAsset, error) {
// GetLength returns length // GetLength returns length
func (m *BinAsset) GetLength() int { func (m *BinAsset) GetLength() int {
return m.Length return m.length
} }
// Read reads the asset // Read reads the asset
func (m *BinAsset) Read(p []byte) (int, error) { func (m *BinAsset) Read(p []byte) (int, error) {
if m.Length == 0 { if m.GetLength() == 0 {
return 0, fmt.Errorf("attempted read from a 0 length asset") return 0, fmt.Errorf("attempted read from a 0 length asset")
} }
return m.reader.Read(p) return m.reader.Read(p)

View File

@ -39,6 +39,7 @@ type Bootstrapper interface {
UpdateCluster(config.KubernetesConfig) error UpdateCluster(config.KubernetesConfig) error
RestartCluster(config.KubernetesConfig) error RestartCluster(config.KubernetesConfig) error
DeleteCluster(config.KubernetesConfig) error DeleteCluster(config.KubernetesConfig) error
WaitCluster(config.KubernetesConfig) error
// LogCommands returns a map of log type to a command which will display that log. // LogCommands returns a map of log type to a command which will display that log.
LogCommands(LogOptions) map[string]string LogCommands(LogOptions) map[string]string
SetupCerts(cfg config.KubernetesConfig) error SetupCerts(cfg config.KubernetesConfig) error

View File

@ -33,6 +33,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
@ -70,7 +71,6 @@ type pod struct {
// PodsByLayer are queries we run when health checking, sorted roughly by dependency layer // PodsByLayer are queries we run when health checking, sorted roughly by dependency layer
var PodsByLayer = []pod{ var PodsByLayer = []pod{
{"apiserver", "component", "kube-apiserver"},
{"proxy", "k8s-app", "kube-proxy"}, {"proxy", "k8s-app", "kube-proxy"},
{"etcd", "component", "etcd"}, {"etcd", "component", "etcd"},
{"scheduler", "component", "kube-scheduler"}, {"scheduler", "component", "kube-scheduler"},
@ -214,20 +214,10 @@ func (k *Bootstrapper) StartCluster(k8s config.KubernetesConfig) error {
} }
} }
if err := waitForPods(k8s, false); err != nil {
return errors.Wrap(err, "wait")
}
glog.Infof("Configuring cluster permissions ...") glog.Infof("Configuring cluster permissions ...")
if err := util.RetryAfter(100, elevateKubeSystemPrivileges, time.Millisecond*500); err != nil { if err := util.RetryAfter(100, elevateKubeSystemPrivileges, time.Millisecond*500); err != nil {
return errors.Wrap(err, "timed out waiting to elevate kube-system RBAC privileges") return errors.Wrap(err, "timed out waiting to elevate kube-system RBAC privileges")
} }
// Make sure elevating privileges didn't screw anything up
if err := waitForPods(k8s, true); err != nil {
return errors.Wrap(err, "wait")
}
return nil return nil
} }
@ -260,37 +250,37 @@ func addAddons(files *[]assets.CopyableFile, data interface{}) error {
return nil return nil
} }
// waitForPods waits until the important Kubernetes pods are in running state // WaitCluster blocks until Kubernetes appears to be healthy.
func waitForPods(k8s config.KubernetesConfig, quiet bool) error { func (k *Bootstrapper) WaitCluster(k8s config.KubernetesConfig) error {
// Do not wait for "k8s-app" pods in the case of CNI, as they are managed // Do not wait for "k8s-app" pods in the case of CNI, as they are managed
// by a CNI plugin which is usually started after minikube has been brought // 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. // up. Otherwise, minikube won't start, as "k8s-app" pods are not ready.
componentsOnly := k8s.NetworkPlugin == "cni" componentsOnly := k8s.NetworkPlugin == "cni"
console.OutStyle("waiting-pods", "Verifying:")
if !quiet {
console.OutStyle("waiting-pods", "Waiting for:")
}
client, err := util.GetClient() client, err := util.GetClient()
if err != nil { if err != nil {
return errors.Wrap(err, "k8s client") return errors.Wrap(err, "k8s client")
} }
// 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")
if err := k.waitForAPIServer(k8s); err != nil {
return errors.Wrap(err, "waiting for apiserver")
}
for _, p := range PodsByLayer { for _, p := range PodsByLayer {
if componentsOnly && p.key != "component" { if componentsOnly && p.key != "component" {
continue continue
} }
if !quiet {
console.Out(" %s", p.name) console.Out(" %s", p.name)
}
selector := labels.SelectorFromSet(labels.Set(map[string]string{p.key: p.value})) selector := labels.SelectorFromSet(labels.Set(map[string]string{p.key: p.value}))
if err := util.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil { if err := util.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
return errors.Wrap(err, fmt.Sprintf("waiting for %s=%s", p.key, p.value)) return errors.Wrap(err, fmt.Sprintf("waiting for %s=%s", p.key, p.value))
} }
} }
if !quiet {
console.OutLn("") console.OutLn("")
}
return nil return nil
} }
@ -308,11 +298,13 @@ func (k *Bootstrapper) RestartCluster(k8s config.KubernetesConfig) error {
controlPlane = "control-plane" controlPlane = "control-plane"
} }
configPath := constants.KubeadmConfigFile
baseCmd := fmt.Sprintf("sudo kubeadm %s", phase)
cmds := []string{ cmds := []string{
fmt.Sprintf("sudo kubeadm %s phase certs all --config %s", phase, constants.KubeadmConfigFile), fmt.Sprintf("%s phase certs all --config %s", baseCmd, configPath),
fmt.Sprintf("sudo kubeadm %s phase kubeconfig all --config %s", phase, constants.KubeadmConfigFile), fmt.Sprintf("%s phase kubeconfig all --config %s", baseCmd, configPath),
fmt.Sprintf("sudo kubeadm %s phase %s all --config %s", phase, controlPlane, constants.KubeadmConfigFile), fmt.Sprintf("%s phase %s all --config %s", baseCmd, controlPlane, configPath),
fmt.Sprintf("sudo kubeadm %s phase etcd local --config %s", phase, constants.KubeadmConfigFile), fmt.Sprintf("%s phase etcd local --config %s", baseCmd, configPath),
} }
// Run commands one at a time so that it is easier to root cause failures. // Run commands one at a time so that it is easier to root cause failures.
@ -322,23 +314,32 @@ func (k *Bootstrapper) RestartCluster(k8s config.KubernetesConfig) error {
} }
} }
if err := waitForPods(k8s, false); err != nil { if err := k.waitForAPIServer(k8s); err != nil {
return errors.Wrap(err, "wait") return errors.Wrap(err, "waiting for apiserver")
} }
// restart the proxy and coredns
console.OutStyle("reconfiguring", "Updating kube-proxy configuration ...") if err := k.c.Run(fmt.Sprintf("%s phase addon all --config %s", baseCmd, configPath)); err != nil {
if err = util.RetryAfter(5, func() error { return updateKubeProxyConfigMap(k8s) }, 5*time.Second); err != nil { return errors.Wrapf(err, "addon phase")
return errors.Wrap(err, "restarting kube-proxy")
} }
// Make sure the kube-proxy restart didn't screw anything up.
if err := waitForPods(k8s, true); err != nil {
return errors.Wrap(err, "wait")
}
return nil return nil
} }
// waitForAPIServer waits for the apiserver to start up
func (k *Bootstrapper) waitForAPIServer(k8s config.KubernetesConfig) error {
glog.Infof("Waiting for apiserver ...")
return wait.PollImmediate(time.Millisecond*200, time.Minute*1, func() (bool, error) {
status, err := k.GetAPIServerStatus(net.ParseIP(k8s.NodeIP), k8s.NodePort)
glog.Infof("status: %s, err: %v", status, err)
if err != nil {
return false, err
}
if status != "Running" {
return false, nil
}
return true, nil
})
}
// DeleteCluster removes the components that were started earlier // DeleteCluster removes the components that were started earlier
func (k *Bootstrapper) DeleteCluster(k8s config.KubernetesConfig) error { func (k *Bootstrapper) DeleteCluster(k8s config.KubernetesConfig) error {
cmd := fmt.Sprintf("sudo kubeadm reset --force") cmd := fmt.Sprintf("sudo kubeadm reset --force")

View File

@ -17,23 +17,17 @@ limitations under the License.
package kubeadm package kubeadm
import ( import (
"bytes"
"encoding/json" "encoding/json"
"html/template"
"net" "net"
"strings"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/pkg/errors" "github.com/pkg/errors"
clientv1 "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
rbacv1beta1 "k8s.io/api/rbac/v1beta1" rbac "k8s.io/api/rbac/v1beta1"
apierrs "k8s.io/apimachinery/pkg/api/errors" apierr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/service" "k8s.io/minikube/pkg/minikube/service"
"k8s.io/minikube/pkg/util" "k8s.io/minikube/pkg/util"
@ -52,7 +46,7 @@ func unmarkMaster() error {
if err != nil { if err != nil {
return errors.Wrap(err, "getting core client") return errors.Wrap(err, "getting core client")
} }
n, err := client.Nodes().Get(master, v1.GetOptions{}) n, err := client.Nodes().Get(master, meta.GetOptions{})
if err != nil { if err != nil {
return errors.Wrapf(err, "getting node %s", master) return errors.Wrapf(err, "getting node %s", master)
} }
@ -62,7 +56,7 @@ func unmarkMaster() error {
return errors.Wrap(err, "json marshalling data before patch") return errors.Wrap(err, "json marshalling data before patch")
} }
newTaints := []clientv1.Taint{} newTaints := []core.Taint{}
for _, taint := range n.Spec.Taints { for _, taint := range n.Spec.Taints {
if taint.Key == masterTaint { if taint.Key == masterTaint {
continue continue
@ -77,13 +71,13 @@ func unmarkMaster() error {
return errors.Wrapf(err, "json marshalling data after patch") return errors.Wrapf(err, "json marshalling data after patch")
} }
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, clientv1.Node{}) patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, core.Node{})
if err != nil { if err != nil {
return errors.Wrap(err, "creating strategic patch") return errors.Wrap(err, "creating strategic patch")
} }
if _, err := client.Nodes().Patch(n.Name, types.StrategicMergePatchType, patchBytes); err != nil { if _, err := client.Nodes().Patch(n.Name, types.StrategicMergePatchType, patchBytes); err != nil {
if apierrs.IsConflict(err) { if apierr.IsConflict(err) {
return errors.Wrap(err, "strategic patch conflict") return errors.Wrap(err, "strategic patch conflict")
} }
return errors.Wrap(err, "applying strategic patch") return errors.Wrap(err, "applying strategic patch")
@ -100,24 +94,24 @@ func elevateKubeSystemPrivileges() error {
if err != nil { if err != nil {
return errors.Wrap(err, "getting clientset") return errors.Wrap(err, "getting clientset")
} }
clusterRoleBinding := &rbacv1beta1.ClusterRoleBinding{ clusterRoleBinding := &rbac.ClusterRoleBinding{
ObjectMeta: v1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: rbacName, Name: rbacName,
}, },
Subjects: []rbacv1beta1.Subject{ Subjects: []rbac.Subject{
{ {
Kind: "ServiceAccount", Kind: "ServiceAccount",
Name: "default", Name: "default",
Namespace: "kube-system", Namespace: "kube-system",
}, },
}, },
RoleRef: rbacv1beta1.RoleRef{ RoleRef: rbac.RoleRef{
Kind: "ClusterRole", Kind: "ClusterRole",
Name: "cluster-admin", Name: "cluster-admin",
}, },
} }
if _, err := client.RbacV1beta1().ClusterRoleBindings().Get(rbacName, metav1.GetOptions{}); err == nil { if _, err := client.RbacV1beta1().ClusterRoleBindings().Get(rbacName, meta.GetOptions{}); err == nil {
glog.Infof("Role binding %s already exists. Skipping creation.", rbacName) glog.Infof("Role binding %s already exists. Skipping creation.", rbacName)
return nil return nil
} }
@ -131,98 +125,3 @@ func elevateKubeSystemPrivileges() error {
} }
return nil return nil
} }
const (
kubeconfigConf = "kubeconfig.conf"
kubeProxyConfigmapTmpl = `apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
server: https://{{.AdvertiseAddress}}:{{.APIServerPort}}
name: default
contexts:
- context:
cluster: default
namespace: default
user: default
name: default
current-context: default
users:
- name: default
user:
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
`
)
// updateKubeProxyConfigMap updates the IP & port kube-proxy listens on, and restarts it.
func updateKubeProxyConfigMap(k8s config.KubernetesConfig) error {
client, err := util.GetClient()
if err != nil {
return errors.Wrap(err, "getting k8s client")
}
selector := labels.SelectorFromSet(labels.Set(map[string]string{"k8s-app": "kube-proxy"}))
if err := util.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
return errors.Wrap(err, "kube-proxy not running")
}
cfgMap, err := client.CoreV1().ConfigMaps("kube-system").Get("kube-proxy", metav1.GetOptions{})
if err != nil {
return &util.RetriableError{Err: errors.Wrap(err, "getting kube-proxy configmap")}
}
glog.Infof("kube-proxy config: %v", cfgMap.Data[kubeconfigConf])
t := template.Must(template.New("kubeProxyTmpl").Parse(kubeProxyConfigmapTmpl))
opts := struct {
AdvertiseAddress string
APIServerPort int
}{
AdvertiseAddress: k8s.NodeIP,
APIServerPort: k8s.NodePort,
}
kubeconfig := bytes.Buffer{}
if err := t.Execute(&kubeconfig, opts); err != nil {
return errors.Wrap(err, "executing kube proxy configmap template")
}
if cfgMap.Data == nil {
cfgMap.Data = map[string]string{}
}
updated := strings.TrimSuffix(kubeconfig.String(), "\n")
glog.Infof("updated kube-proxy config: %s", updated)
// An optimization, but also one that's unlikely, as kubeadm writes the address as 'localhost'
if cfgMap.Data[kubeconfigConf] == updated {
glog.Infof("kube-proxy config appears to require no change, not restarting kube-proxy")
return nil
}
cfgMap.Data[kubeconfigConf] = updated
// Make this step retriable, as it can fail with:
// "Operation cannot be fulfilled on configmaps "kube-proxy": the object has been modified; please apply your changes to the latest version and try again"
if _, err := client.CoreV1().ConfigMaps("kube-system").Update(cfgMap); err != nil {
return &util.RetriableError{Err: errors.Wrap(err, "updating configmap")}
}
pods, err := client.CoreV1().Pods("kube-system").List(metav1.ListOptions{
LabelSelector: "k8s-app=kube-proxy",
})
if err != nil {
return errors.Wrap(err, "listing kube-proxy pods")
}
for _, pod := range pods.Items {
// Retriable, as known to fail with: pods "<name>" not found
if err := client.CoreV1().Pods(pod.Namespace).Delete(pod.Name, &metav1.DeleteOptions{}); err != nil {
return &util.RetriableError{Err: errors.Wrapf(err, "deleting pod %+v", pod)}
}
}
// Wait for the scheduler to restart kube-proxy
if err := util.WaitForPodsWithLabelRunning(client, "kube-system", selector); err != nil {
return errors.Wrap(err, "kube-proxy not running")
}
return nil
}

View File

@ -82,7 +82,7 @@ func NewComponentExtraArgs(opts util.ExtraOptionSlice, version semver.Version, f
var kubeadmExtraArgs []ComponentExtraArgs var kubeadmExtraArgs []ComponentExtraArgs
for _, extraOpt := range opts { for _, extraOpt := range opts {
if _, ok := componentToKubeadmConfigKey[extraOpt.Component]; !ok { if _, ok := componentToKubeadmConfigKey[extraOpt.Component]; !ok {
return nil, fmt.Errorf("Unknown component %s. Valid components and kubeadm config are %v", componentToKubeadmConfigKey, componentToKubeadmConfigKey) return nil, fmt.Errorf("unknown component %q. valid components are: %v", componentToKubeadmConfigKey, componentToKubeadmConfigKey)
} }
} }
@ -151,7 +151,7 @@ func ParseFeatureArgs(featureGates string) (map[string]bool, string, error) {
// feature gates for kubeadm // feature gates for kubeadm
func Supports(featureName string) bool { func Supports(featureName string) bool {
for k := range features.InitFeatureGates { for k := range features.InitFeatureGates {
if featureName == string(k) { if featureName == k {
return true return true
} }
} }
@ -310,7 +310,7 @@ func DefaultOptionsForComponentAndVersion(component string, version semver.Versi
if opts.Option.Component == component { if opts.Option.Component == component {
if VersionIsBetween(version, opts.GreaterThanOrEqual, opts.LessThanOrEqual) { if VersionIsBetween(version, opts.GreaterThanOrEqual, opts.LessThanOrEqual) {
if val, ok := versionedOpts[opts.Option.Key]; ok { if val, ok := versionedOpts[opts.Option.Key]; ok {
return nil, fmt.Errorf("Flag %s=%s already set %s=%s", opts.Option.Key, opts.Option.Value, opts.Option.Key, val) return nil, fmt.Errorf("flag %s=%q already set %s=%q", opts.Option.Key, opts.Option.Value, opts.Option.Key, val)
} }
versionedOpts[opts.Option.Key] = opts.Option.Value versionedOpts[opts.Option.Key] = opts.Option.Value
} }

View File

@ -46,15 +46,13 @@ import (
pkgutil "k8s.io/minikube/pkg/util" pkgutil "k8s.io/minikube/pkg/util"
) )
const (
defaultVirtualboxNicType = "virtio"
)
//This init function is used to set the logtostderr variable to false so that INFO level log info does not clutter the CLI //This init function is used to set the logtostderr variable to false so that INFO level log info does not clutter the CLI
//INFO lvl logging is displayed due to the kubernetes api calling flag.Set("logtostderr", "true") in its init() //INFO lvl logging is displayed due to the kubernetes api calling flag.Set("logtostderr", "true") in its init()
//see: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/util/logs/logs.go#L32-L34 //see: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/util/logs/logs.go#L32-L34
func init() { func init() {
flag.Set("logtostderr", "false") if err := flag.Set("logtostderr", "false"); err != nil {
exit.WithError("unable to set logtostderr", err)
}
// Setting the default client to native gives much better performance. // Setting the default client to native gives much better performance.
ssh.SetDefaultClient(ssh.Native) ssh.SetDefaultClient(ssh.Native)
@ -74,7 +72,7 @@ func CacheISO(config cfg.MachineConfig) error {
func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) { func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) {
exists, err := api.Exists(cfg.GetMachineName()) exists, err := api.Exists(cfg.GetMachineName())
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "machine name: %s", cfg.GetMachineName()) return nil, errors.Wrapf(err, "exists: %s", cfg.GetMachineName())
} }
if !exists { if !exists {
glog.Infoln("Machine does not exist... provisioning new machine") glog.Infoln("Machine does not exist... provisioning new machine")
@ -294,7 +292,7 @@ func engineOptions(config cfg.MachineConfig) *engine.Options {
return &o return &o
} }
func preCreateHost(config *cfg.MachineConfig) error { func preCreateHost(config *cfg.MachineConfig) {
switch config.VMDriver { switch config.VMDriver {
case "kvm": case "kvm":
if viper.GetBool(cfg.ShowDriverDeprecationNotification) { if viper.GetBool(cfg.ShowDriverDeprecationNotification) {
@ -318,16 +316,10 @@ To disable this message, run [minikube config set WantShowDriverDeprecationNotif
To disable this message, run [minikube config set WantShowDriverDeprecationNotification false]`) To disable this message, run [minikube config set WantShowDriverDeprecationNotification false]`)
} }
} }
return nil
} }
func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) { func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error) {
err := preCreateHost(&config) preCreateHost(&config)
if err != nil {
return nil, err
}
console.OutStyle("starting-vm", "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...", config.VMDriver, config.CPUs, config.Memory, config.DiskSize) console.OutStyle("starting-vm", "Creating %s VM (CPUs=%d, Memory=%dMB, Disk=%dMB) ...", config.VMDriver, config.CPUs, config.Memory, config.DiskSize)
def, err := registry.Driver(config.VMDriver) def, err := registry.Driver(config.VMDriver)
if err != nil { if err != nil {
@ -416,6 +408,16 @@ func GetVMHostIP(host *host.Host) (net.IP, error) {
return ip, nil return ip, nil
case "xhyve", "hyperkit": case "xhyve", "hyperkit":
return net.ParseIP("192.168.64.1"), nil return net.ParseIP("192.168.64.1"), nil
case "vmware":
vmIPString, err := host.Driver.GetIP()
if err != nil {
return []byte{}, errors.Wrap(err, "Error getting VM IP address")
}
vmIP := net.ParseIP(vmIPString).To4()
if vmIP == nil {
return []byte{}, errors.Wrap(err, "Error converting VM IP address to IPv4 address")
}
return net.IPv4(vmIP[0], vmIP[1], vmIP[2], byte(1)), nil
default: default:
return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver") return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver")
} }

View File

@ -214,7 +214,11 @@ func TestStopHostError(t *testing.T) {
func TestStopHost(t *testing.T) { func TestStopHost(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
h, _ := createHost(api, defaultMachineConfig) h, err := createHost(api, defaultMachineConfig)
if err != nil {
t.Errorf("createHost failed: %v", err)
}
if err := StopHost(api); err != nil { if err := StopHost(api); err != nil {
t.Fatal("An error should be thrown when stopping non-existing machine.") t.Fatal("An error should be thrown when stopping non-existing machine.")
} }
@ -225,7 +229,9 @@ func TestStopHost(t *testing.T) {
func TestDeleteHost(t *testing.T) { func TestDeleteHost(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
createHost(api, defaultMachineConfig) if _, err := createHost(api, defaultMachineConfig); err != nil {
t.Errorf("createHost failed: %v", err)
}
if err := DeleteHost(api); err != nil { if err := DeleteHost(api); err != nil {
t.Fatalf("Unexpected error deleting host: %v", err) t.Fatalf("Unexpected error deleting host: %v", err)
@ -234,7 +240,10 @@ func TestDeleteHost(t *testing.T) {
func TestDeleteHostErrorDeletingVM(t *testing.T) { func TestDeleteHostErrorDeletingVM(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
h, _ := createHost(api, defaultMachineConfig) h, err := createHost(api, defaultMachineConfig)
if err != nil {
t.Errorf("createHost failed: %v", err)
}
d := &tests.MockDriver{RemoveError: true} d := &tests.MockDriver{RemoveError: true}
@ -248,7 +257,9 @@ func TestDeleteHostErrorDeletingVM(t *testing.T) {
func TestDeleteHostErrorDeletingFiles(t *testing.T) { func TestDeleteHostErrorDeletingFiles(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
api.RemoveError = true api.RemoveError = true
createHost(api, defaultMachineConfig) if _, err := createHost(api, defaultMachineConfig); err != nil {
t.Errorf("createHost failed: %v", err)
}
if err := DeleteHost(api); err == nil { if err := DeleteHost(api); err == nil {
t.Fatal("Expected error deleting host.") t.Fatal("Expected error deleting host.")
@ -270,10 +281,15 @@ func TestGetHostStatus(t *testing.T) {
checkState(state.None.String()) checkState(state.None.String())
createHost(api, defaultMachineConfig) if _, err := createHost(api, defaultMachineConfig); err != nil {
t.Errorf("createHost failed: %v", err)
}
checkState(state.Running.String()) checkState(state.Running.String())
StopHost(api) if err := StopHost(api); err != nil {
t.Errorf("StopHost failed: %v", err)
}
checkState(state.Stopped.String()) checkState(state.Stopped.String())
} }

View File

@ -76,13 +76,13 @@ func ReadConfig() (MinikubeConfig, error) {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return make(map[string]interface{}), nil return make(map[string]interface{}), nil
} }
return nil, fmt.Errorf("Could not open file %s: %v", constants.ConfigFile, err) return nil, fmt.Errorf("open %s: %v", constants.ConfigFile, err)
} }
defer f.Close() defer f.Close()
m, err := decode(f) m, err := decode(f)
if err != nil { if err != nil {
return nil, fmt.Errorf("Could not decode config %s: %v", constants.ConfigFile, err) return nil, fmt.Errorf("decode %s: %v", constants.ConfigFile, err)
} }
return m, nil return m, nil

View File

@ -70,95 +70,86 @@ func HasStyle(style string) bool {
} }
// OutStyle writes a stylized and formatted message to stdout // OutStyle writes a stylized and formatted message to stdout
func OutStyle(style, format string, a ...interface{}) error { func OutStyle(style, format string, a ...interface{}) {
outStyled, err := applyStyle(style, useColor, format, a...) outStyled, err := applyStyle(style, useColor, format, a...)
if err != nil { if err != nil {
glog.Errorf("applyStyle(%s): %v", style, err) glog.Errorf("applyStyle(%s): %v", style, err)
if oerr := OutLn(format, a...); oerr != nil {
glog.Errorf("Out failed: %v", oerr)
}
return err
} }
// escape any outstanding '%' signs so that they don't get interpreted // escape any outstanding '%' signs so that they don't get interpreted
// as a formatting directive down the line // as a formatting directive down the line
outStyled = strings.Replace(outStyled, "%", "%%", -1) outStyled = strings.Replace(outStyled, "%", "%%", -1)
Out(outStyled)
return Out(outStyled)
} }
// Out writes a basic formatted string to stdout // Out writes a basic formatted string to stdout
func Out(format string, a ...interface{}) error { func Out(format string, a ...interface{}) {
p := message.NewPrinter(preferredLanguage) p := message.NewPrinter(preferredLanguage)
if outFile == nil { if outFile == nil {
if _, err := p.Fprintf(os.Stdout, "(stdout unset)"+format, a...); err != nil { glog.Warningf("[unset outFile]: %s", fmt.Sprintf(format, a...))
return err return
}
return fmt.Errorf("no output file has been set")
} }
_, err := p.Fprintf(outFile, format, a...) _, err := p.Fprintf(outFile, format, a...)
return err if err != nil {
glog.Errorf("Fprintf failed: %v", err)
}
} }
// OutLn writes a basic formatted string with a newline to stdout // OutLn writes a basic formatted string with a newline to stdout
func OutLn(format string, a ...interface{}) error { func OutLn(format string, a ...interface{}) {
return Out(format+"\n", a...) Out(format+"\n", a...)
} }
// ErrStyle writes a stylized and formatted error message to stderr // ErrStyle writes a stylized and formatted error message to stderr
func ErrStyle(style, format string, a ...interface{}) error { func ErrStyle(style, format string, a ...interface{}) {
format, err := applyStyle(style, useColor, format, a...) format, err := applyStyle(style, useColor, format, a...)
if err != nil { if err != nil {
glog.Errorf("applyStyle(%s): %v", style, err) glog.Errorf("applyStyle(%s): %v", style, err)
if oerr := ErrLn(format, a...); oerr != nil { ErrLn(format, a...)
glog.Errorf("Err(%s) failed: %v", format, oerr)
}
return err
} }
// escape any outstanding '%' signs so that they don't get interpreted // escape any outstanding '%' signs so that they don't get interpreted
// as a formatting directive down the line // as a formatting directive down the line
format = strings.Replace(format, "%", "%%", -1) format = strings.Replace(format, "%", "%%", -1)
Err(format)
return Err(format)
} }
// Err writes a basic formatted string to stderr // Err writes a basic formatted string to stderr
func Err(format string, a ...interface{}) error { func Err(format string, a ...interface{}) {
p := message.NewPrinter(preferredLanguage) p := message.NewPrinter(preferredLanguage)
if errFile == nil { if errFile == nil {
if _, err := p.Fprintf(os.Stderr, "(stderr unset)"+format, a...); err != nil { glog.Errorf("[unset errFile]: %s", fmt.Sprintf(format, a...))
return err return
}
return fmt.Errorf("no error file has been set")
} }
_, err := p.Fprintf(errFile, format, a...) _, err := p.Fprintf(errFile, format, a...)
return err if err != nil {
glog.Errorf("Fprint failed: %v", err)
}
} }
// ErrLn writes a basic formatted string with a newline to stderr // ErrLn writes a basic formatted string with a newline to stderr
func ErrLn(format string, a ...interface{}) error { func ErrLn(format string, a ...interface{}) {
return Err(format+"\n", a...) Err(format+"\n", a...)
} }
// Success is a shortcut for writing a styled success message to stdout // Success is a shortcut for writing a styled success message to stdout
func Success(format string, a ...interface{}) error { func Success(format string, a ...interface{}) {
return OutStyle("success", format, a...) OutStyle("success", format, a...)
} }
// Fatal is a shortcut for writing a styled fatal message to stderr // Fatal is a shortcut for writing a styled fatal message to stderr
func Fatal(format string, a ...interface{}) error { func Fatal(format string, a ...interface{}) {
return ErrStyle("fatal", format, a...) ErrStyle("fatal", format, a...)
} }
// Warning is a shortcut for writing a styled warning message to stderr // Warning is a shortcut for writing a styled warning message to stderr
func Warning(format string, a ...interface{}) error { func Warning(format string, a ...interface{}) {
return ErrStyle("warning", format, a...) ErrStyle("warning", format, a...)
} }
// Failure is a shortcut for writing a styled failure message to stderr // Failure is a shortcut for writing a styled failure message to stderr
func Failure(format string, a ...interface{}) error { func Failure(format string, a ...interface{}) {
return ErrStyle("failure", format, a...) ErrStyle("failure", format, a...)
} }
// SetPreferredLanguageTag configures which language future messages should use. // SetPreferredLanguageTag configures which language future messages should use.
@ -205,7 +196,9 @@ func DetermineLocale() {
glog.Warningf("Getting system locale failed: %s", err) glog.Warningf("Getting system locale failed: %s", err)
locale = "" locale = ""
} }
SetPreferredLanguage(locale) if err := SetPreferredLanguage(locale); err != nil {
glog.Errorf("Unable to set preferred language: %v", err)
}
} }
// wantsColor determines if the user might want colorized output. // wantsColor determines if the user might want colorized output.

View File

@ -71,9 +71,7 @@ func TestOutStyle(t *testing.T) {
os.Setenv(OverrideEnv, strconv.FormatBool(override)) os.Setenv(OverrideEnv, strconv.FormatBool(override))
f := newFakeFile() f := newFakeFile()
SetOutFile(f) SetOutFile(f)
if err := OutStyle(tc.style, tc.message, tc.params...); err != nil { OutStyle(tc.style, tc.message, tc.params...)
t.Errorf("unexpected error: %q", err)
}
got := f.String() got := f.String()
want := tc.wantASCII want := tc.wantASCII
if override { if override {
@ -112,9 +110,7 @@ func TestOut(t *testing.T) {
f := newFakeFile() f := newFakeFile()
SetOutFile(f) SetOutFile(f)
ErrLn("unrelated message") ErrLn("unrelated message")
if err := Out(tc.format, tc.arg); err != nil { Out(tc.format, tc.arg)
t.Errorf("unexpected error: %q", err)
}
got := f.String() got := f.String()
if got != tc.want { if got != tc.want {
t.Errorf("Out(%s, %s) = %q, want %q", tc.format, tc.arg, got, tc.want) t.Errorf("Out(%s, %s) = %q, want %q", tc.format, tc.arg, got, tc.want)
@ -127,10 +123,7 @@ func TestErr(t *testing.T) {
os.Setenv(OverrideEnv, "0") os.Setenv(OverrideEnv, "0")
f := newFakeFile() f := newFakeFile()
SetErrFile(f) SetErrFile(f)
if err := Err("xyz123 %s\n", "%s%%%d"); err != nil { Err("xyz123 %s\n", "%s%%%d")
t.Errorf("unexpected error: %q", err)
}
OutLn("unrelated message") OutLn("unrelated message")
got := f.String() got := f.String()
want := "xyz123 %s%%%d\n" want := "xyz123 %s%%%d\n"
@ -144,9 +137,7 @@ func TestErrStyle(t *testing.T) {
os.Setenv(OverrideEnv, "1") os.Setenv(OverrideEnv, "1")
f := newFakeFile() f := newFakeFile()
SetErrFile(f) SetErrFile(f)
if err := ErrStyle("fatal", "error: %s", "%s%%%d"); err != nil { ErrStyle("fatal", "error: %s", "%s%%%d")
t.Errorf("unexpected error: %q", err)
}
got := f.String() got := f.String()
want := "💣 error: %s%%%d\n" want := "💣 error: %s%%%d\n"
if got != want { if got != want {

View File

@ -53,11 +53,10 @@ func GetMinipath() string {
// ArchTag returns the archtag for images // ArchTag returns the archtag for images
func ArchTag(hasTag bool) string { func ArchTag(hasTag bool) string {
if runtime.GOARCH == "amd64" && hasTag == false { if runtime.GOARCH == "amd64" && !hasTag {
return ":" return ":"
} else {
return "-" + runtime.GOARCH + ":"
} }
return "-" + runtime.GOARCH + ":"
} }
// SupportedVMDrivers is a list of supported drivers on all platforms. Currently // SupportedVMDrivers is a list of supported drivers on all platforms. Currently

View File

@ -149,7 +149,7 @@ func (f *FakeRunner) Run(cmd string) error {
} }
// docker is a fake implementation of docker // docker is a fake implementation of docker
func (f *FakeRunner) docker(args []string, root bool) (string, error) { func (f *FakeRunner) docker(args []string, _ bool) (string, error) {
switch cmd := args[0]; cmd { switch cmd := args[0]; cmd {
case "ps": case "ps":
// ps -a --filter="name=apiserver" --format="{{.ID}}" // ps -a --filter="name=apiserver" --format="{{.ID}}"
@ -194,25 +194,23 @@ func (f *FakeRunner) docker(args []string, root bool) (string, error) {
} }
// crio is a fake implementation of crio // crio is a fake implementation of crio
func (f *FakeRunner) crio(args []string, root bool) (string, error) { func (f *FakeRunner) crio(args []string, _ bool) (string, error) {
switch cmd := args[0]; cmd { if args[0] == "--version" {
case "--version":
return "crio version 1.13.0", nil return "crio version 1.13.0", nil
} }
return "", nil return "", nil
} }
// containerd is a fake implementation of containerd // containerd is a fake implementation of containerd
func (f *FakeRunner) containerd(args []string, root bool) (string, error) { func (f *FakeRunner) containerd(args []string, _ bool) (string, error) {
switch cmd := args[0]; cmd { if args[0] == "--version" {
case "--version":
return "containerd github.com/containerd/containerd v1.2.0 c4446665cb9c30056f4998ed953e6d4ff22c7c39", nil return "containerd github.com/containerd/containerd v1.2.0 c4446665cb9c30056f4998ed953e6d4ff22c7c39", nil
} }
return "", nil return "", nil
} }
// crictl is a fake implementation of crictl // crictl is a fake implementation of crictl
func (f *FakeRunner) crictl(args []string, root bool) (string, error) { func (f *FakeRunner) crictl(args []string, _ bool) (string, error) {
switch cmd := args[0]; cmd { switch cmd := args[0]; cmd {
case "ps": case "ps":
// crictl ps -a --name=apiserver --state=Running --quiet // crictl ps -a --name=apiserver --state=Running --quiet
@ -461,7 +459,9 @@ func TestContainerFunctions(t *testing.T) {
} }
// Stop the containers and assert that they have disappeared // Stop the containers and assert that they have disappeared
cr.StopContainers(got) if err := cr.StopContainers(got); err != nil {
t.Fatalf("stop failed: %v", err)
}
got, err = cr.ListContainers("apiserver") got, err = cr.ListContainers("apiserver")
if err != nil { if err != nil {
t.Fatalf("ListContainers: %v", err) t.Fatalf("ListContainers: %v", err)
@ -482,7 +482,9 @@ func TestContainerFunctions(t *testing.T) {
} }
// Kill the containers and assert that they have disappeared // Kill the containers and assert that they have disappeared
cr.KillContainers(got) if err := cr.KillContainers(got); err != nil {
t.Errorf("KillContainers: %v", err)
}
got, err = cr.ListContainers("") got, err = cr.ListContainers("")
if err != nil { if err != nil {
t.Fatalf("ListContainers: %v", err) t.Fatalf("ListContainers: %v", err)

View File

@ -19,6 +19,8 @@ limitations under the License.
package hyperkit package hyperkit
import ( import (
"fmt"
"github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/drivers"
"github.com/pborman/uuid" "github.com/pborman/uuid"
"k8s.io/minikube/pkg/drivers/hyperkit" "k8s.io/minikube/pkg/drivers/hyperkit"
@ -28,11 +30,13 @@ import (
) )
func init() { func init() {
registry.Register(registry.DriverDef{ if err := registry.Register(registry.DriverDef{
Name: "hyperkit", Name: "hyperkit",
Builtin: false, Builtin: false,
ConfigCreator: createHyperkitHost, ConfigCreator: createHyperkitHost,
}) }); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
} }
func createHyperkitHost(config cfg.MachineConfig) interface{} { func createHyperkitHost(config cfg.MachineConfig) interface{} {

View File

@ -29,11 +29,13 @@ import (
) )
func init() { func init() {
registry.Register(registry.DriverDef{ if err := registry.Register(registry.DriverDef{
Name: "kvm", Name: "kvm",
Builtin: false, Builtin: false,
ConfigCreator: createKVMHost, ConfigCreator: createKVMHost,
}) }); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
} }
// Delete this once the following PR is merged: // Delete this once the following PR is merged:

View File

@ -29,11 +29,13 @@ import (
) )
func init() { func init() {
registry.Register(registry.DriverDef{ if err := registry.Register(registry.DriverDef{
Name: "kvm2", Name: "kvm2",
Builtin: false, Builtin: false,
ConfigCreator: createKVM2Host, ConfigCreator: createKVM2Host,
}) }); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
} }
// Delete this once the following PR is merged: // Delete this once the following PR is merged:

View File

@ -1,5 +1,3 @@
// +build linux
/* /*
Copyright 2018 The Kubernetes Authors All rights reserved. Copyright 2018 The Kubernetes Authors All rights reserved.
@ -19,6 +17,8 @@ limitations under the License.
package none package none
import ( import (
"fmt"
"github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/drivers"
"k8s.io/minikube/pkg/drivers/none" "k8s.io/minikube/pkg/drivers/none"
cfg "k8s.io/minikube/pkg/minikube/config" cfg "k8s.io/minikube/pkg/minikube/config"
@ -27,14 +27,16 @@ import (
) )
func init() { func init() {
registry.Register(registry.DriverDef{ if err := registry.Register(registry.DriverDef{
Name: "none", Name: "none",
Builtin: true, Builtin: true,
ConfigCreator: createNoneHost, ConfigCreator: createNoneHost,
DriverCreator: func() drivers.Driver { DriverCreator: func() drivers.Driver {
return none.NewDriver(none.Config{}) return none.NewDriver(none.Config{})
}, },
}) }); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
} }
// createNoneHost creates a none Driver from a MachineConfig // createNoneHost creates a none Driver from a MachineConfig

View File

@ -19,6 +19,8 @@ limitations under the License.
package parallels package parallels
import ( import (
"fmt"
parallels "github.com/Parallels/docker-machine-parallels" parallels "github.com/Parallels/docker-machine-parallels"
"github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config" cfg "k8s.io/minikube/pkg/minikube/config"
@ -27,7 +29,7 @@ import (
) )
func init() { func init() {
registry.Register(registry.DriverDef{ err := registry.Register(registry.DriverDef{
Name: "parallels", Name: "parallels",
Builtin: true, Builtin: true,
ConfigCreator: createParallelsHost, ConfigCreator: createParallelsHost,
@ -35,6 +37,10 @@ func init() {
return parallels.NewDriver("", "") return parallels.NewDriver("", "")
}, },
}) })
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
}
} }
func createParallelsHost(config cfg.MachineConfig) interface{} { func createParallelsHost(config cfg.MachineConfig) interface{} {

View File

@ -17,6 +17,8 @@ limitations under the License.
package virtualbox package virtualbox
import ( import (
"fmt"
"github.com/docker/machine/drivers/virtualbox" "github.com/docker/machine/drivers/virtualbox"
"github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config" cfg "k8s.io/minikube/pkg/minikube/config"
@ -27,7 +29,7 @@ import (
const defaultVirtualboxNicType = "virtio" const defaultVirtualboxNicType = "virtio"
func init() { func init() {
registry.Register(registry.DriverDef{ err := registry.Register(registry.DriverDef{
Name: "virtualbox", Name: "virtualbox",
Builtin: true, Builtin: true,
ConfigCreator: createVirtualboxHost, ConfigCreator: createVirtualboxHost,
@ -35,6 +37,9 @@ func init() {
return virtualbox.NewDriver("", "") return virtualbox.NewDriver("", "")
}, },
}) })
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
}
} }
func createVirtualboxHost(config cfg.MachineConfig) interface{} { func createVirtualboxHost(config cfg.MachineConfig) interface{} {
@ -43,7 +48,7 @@ func createVirtualboxHost(config cfg.MachineConfig) interface{} {
d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO)
d.Memory = config.Memory d.Memory = config.Memory
d.CPU = config.CPUs d.CPU = config.CPUs
d.DiskSize = int(config.DiskSize) d.DiskSize = config.DiskSize
d.HostOnlyCIDR = config.HostOnlyCIDR d.HostOnlyCIDR = config.HostOnlyCIDR
d.NoShare = config.DisableDriverMounts d.NoShare = config.DisableDriverMounts
d.NoVTXCheck = config.NoVTXCheck d.NoVTXCheck = config.NoVTXCheck

View File

@ -17,6 +17,8 @@ limitations under the License.
package vmware package vmware
import ( import (
"fmt"
vmwcfg "github.com/machine-drivers/docker-machine-driver-vmware/pkg/drivers/vmware/config" vmwcfg "github.com/machine-drivers/docker-machine-driver-vmware/pkg/drivers/vmware/config"
cfg "k8s.io/minikube/pkg/minikube/config" cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
@ -24,11 +26,14 @@ import (
) )
func init() { func init() {
registry.Register(registry.DriverDef{ err := registry.Register(registry.DriverDef{
Name: "vmware", Name: "vmware",
Builtin: false, Builtin: false,
ConfigCreator: createVMwareHost, ConfigCreator: createVMwareHost,
}) })
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
}
} }
func createVMwareHost(config cfg.MachineConfig) interface{} { func createVMwareHost(config cfg.MachineConfig) interface{} {

View File

@ -19,6 +19,8 @@ limitations under the License.
package vmwarefusion package vmwarefusion
import ( import (
"fmt"
"github.com/docker/machine/drivers/vmwarefusion" "github.com/docker/machine/drivers/vmwarefusion"
"github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config" cfg "k8s.io/minikube/pkg/minikube/config"
@ -27,14 +29,16 @@ import (
) )
func init() { func init() {
registry.Register(registry.DriverDef{ if err := registry.Register(registry.DriverDef{
Name: "vmwarefusion", Name: "vmwarefusion",
Builtin: true, Builtin: true,
ConfigCreator: createVMwareFusionHost, ConfigCreator: createVMwareFusionHost,
DriverCreator: func() drivers.Driver { DriverCreator: func() drivers.Driver {
return vmwarefusion.NewDriver("", "") return vmwarefusion.NewDriver("", "")
}, },
}) }); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
} }
func createVMwareFusionHost(config cfg.MachineConfig) interface{} { func createVMwareFusionHost(config cfg.MachineConfig) interface{} {

View File

@ -34,7 +34,7 @@ https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#xhyve-driver
` `
func init() { func init() {
registry.Register(registry.DriverDef{ if err := registry.Register(registry.DriverDef{
Name: "xhyve", Name: "xhyve",
Builtin: false, Builtin: false,
ConfigCreator: createXhyveHost, ConfigCreator: createXhyveHost,
@ -43,7 +43,9 @@ func init() {
os.Exit(1) os.Exit(1)
return nil return nil
}, },
}) }); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
} }
type xhyveDriver struct { type xhyveDriver struct {

View File

@ -33,7 +33,7 @@ import (
) )
// rootCauseRe is a regular expression that matches known failure root causes // rootCauseRe is a regular expression that matches known failure root causes
var rootCauseRe = regexp.MustCompile(`^error: |eviction manager: pods.* evicted|unknown flag: --|forbidden.*no providers available|eviction manager:.*evicted`) var rootCauseRe = regexp.MustCompile(`^error: |eviction manager: pods.* evicted|unknown flag: --|forbidden.*no providers available|eviction manager:.*evicted|tls: bad certificate`)
// ignoreRe is a regular expression that matches spurious errors to not surface // ignoreRe is a regular expression that matches spurious errors to not surface
var ignoreCauseRe = regexp.MustCompile("error: no objects passed to apply") var ignoreCauseRe = regexp.MustCompile("error: no objects passed to apply")

View File

@ -34,6 +34,7 @@ func TestIsProblem(t *testing.T) {
{"apiserver-admission #3524", true, "error: unknown flag: --GenericServerRunOptions.AdmissionControl"}, {"apiserver-admission #3524", true, "error: unknown flag: --GenericServerRunOptions.AdmissionControl"},
{"no-providers-available #3818", true, ` kubelet.go:1662] Failed creating a mirror pod for "kube-apiserver-minikube_kube-system(c7d572aebd3d33b17fa78ae6395b6d0a)": pods "kube-apiserver-minikube" is forbidden: no providers available to validate pod request`}, {"no-providers-available #3818", true, ` kubelet.go:1662] Failed creating a mirror pod for "kube-apiserver-minikube_kube-system(c7d572aebd3d33b17fa78ae6395b6d0a)": pods "kube-apiserver-minikube" is forbidden: no providers available to validate pod request`},
{"no-objects-passed-to-apply #4010", false, "error: no objects passed to apply"}, {"no-objects-passed-to-apply #4010", false, "error: no objects passed to apply"},
{"bad-certificate #4251", true, "log.go:172] http: TLS handshake error from 127.0.0.1:49200: remote error: tls: bad certificate"},
} }
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {

View File

@ -133,12 +133,8 @@ func CacheAndLoadImages(images []string) error {
if err != nil { if err != nil {
return err return err
} }
cmdRunner, err := bootstrapper.NewSSHRunner(client), nil runner := bootstrapper.NewSSHRunner(client)
if err != nil { return LoadImages(runner, images, constants.ImageCacheDir)
return err
}
return LoadImages(cmdRunner, images, constants.ImageCacheDir)
} }
// # ParseReference cannot have a : in the directory path // # ParseReference cannot have a : in the directory path
@ -276,7 +272,7 @@ func cleanImageCacheDir() error {
return err return err
} }
func getDstPath(image, dst string) (string, error) { func getDstPath(dst string) (string, error) {
if runtime.GOOS == "windows" && hasWindowsDriveLetter(dst) { if runtime.GOOS == "windows" && hasWindowsDriveLetter(dst) {
// ParseReference does not support a Windows drive letter. // ParseReference does not support a Windows drive letter.
// Therefore, will replace the drive letter to a volume name. // Therefore, will replace the drive letter to a volume name.
@ -302,7 +298,9 @@ func CacheImage(image, dst string) error {
defer func() { defer func() {
log.SetOutput(os.Stdout) log.SetOutput(os.Stdout)
var buf bytes.Buffer var buf bytes.Buffer
io.Copy(&buf, r) if _, err := io.Copy(&buf, r); err != nil {
glog.Errorf("output copy failed: %v", err)
}
glog.Infof(buf.String()) glog.Infof(buf.String())
}() }()
@ -311,7 +309,7 @@ func CacheImage(image, dst string) error {
return nil return nil
} }
dstPath, err := getDstPath(image, dst) dstPath, err := getDstPath(dst)
if err != nil { if err != nil {
return errors.Wrap(err, "getting destination path") return errors.Wrap(err, "getting destination path")
} }

View File

@ -63,7 +63,9 @@ func MaybePrintUpdateText(output io.Writer, url string, lastUpdatePath string) {
return return
} }
if localVersion.Compare(latestVersion) < 0 { if localVersion.Compare(latestVersion) < 0 {
writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()) if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil {
glog.Errorf("write time failed: %v", err)
}
fmt.Fprintf(output, `There is a newer version of minikube available (%s%s). Download it here: fmt.Fprintf(output, `There is a newer version of minikube available (%s%s). Download it here:
%s%s %s%s

View File

@ -54,13 +54,19 @@ func TestShouldCheckURL(t *testing.T) {
// test that update notifications get triggered if it has been longer than 24 hours // test that update notifications get triggered if it has been longer than 24 hours
viper.Set(config.ReminderWaitPeriodInHours, 24) viper.Set(config.ReminderWaitPeriodInHours, 24)
writeTimeToFile(lastUpdateCheckFilePath, time.Time{}) //time.Time{} returns time -> January 1, year 1, 00:00:00.000000000 UTC.
//time.Time{} returns time -> January 1, year 1, 00:00:00.000000000 UTC.
if err := writeTimeToFile(lastUpdateCheckFilePath, time.Time{}); err != nil {
t.Errorf("write failed: %v", err)
}
if !shouldCheckURLVersion(lastUpdateCheckFilePath) { if !shouldCheckURLVersion(lastUpdateCheckFilePath) {
t.Fatalf("shouldCheckURLVersion returned false even though longer than 24 hours since last update") t.Fatalf("shouldCheckURLVersion returned false even though longer than 24 hours since last update")
} }
// test that update notifications do not get triggered if it has been less than 24 hours // test that update notifications do not get triggered if it has been less than 24 hours
writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()) if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil {
t.Errorf("write failed: %v", err)
}
if shouldCheckURLVersion(lastUpdateCheckFilePath) { if shouldCheckURLVersion(lastUpdateCheckFilePath) {
t.Fatalf("shouldCheckURLVersion returned true even though less than 24 hours since last update") t.Fatalf("shouldCheckURLVersion returned true even though less than 24 hours since last update")
} }
@ -78,7 +84,11 @@ func (h *URLHandlerCorrect) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
w.Header().Set("Content-Type", "application/javascript") w.Header().Set("Content-Type", "application/javascript")
fmt.Fprintf(w, string(b)) _, err = fmt.Fprint(w, string(b))
if err != nil {
fmt.Println(err)
return
}
} }
func TestGetLatestVersionFromURLCorrect(t *testing.T) { func TestGetLatestVersionFromURLCorrect(t *testing.T) {

View File

@ -25,6 +25,12 @@ func re(s string) *regexp.Regexp {
// vmProblems are VM related problems // vmProblems are VM related problems
var vmProblems = map[string]match{ var vmProblems = map[string]match{
"HYPERKIT_NO_IP": {
Regexp: re(`IP address never found in dhcp leases file Temporary Error: Could not find an IP address for`),
Advice: "Install the latest minikube hyperkit driver, and run 'minikube delete'",
URL: "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver",
Issues: []int{1926, 4206},
},
"VBOX_NOT_FOUND": { "VBOX_NOT_FOUND": {
Regexp: re(`VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path`), Regexp: re(`VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path`),
Advice: "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver", Advice: "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver",
@ -67,7 +73,7 @@ var vmProblems = map[string]match{
"VBOX_HOST_ADAPTER": { "VBOX_HOST_ADAPTER": {
Regexp: re(`The host-only adapter we just created is not visible`), Regexp: re(`The host-only adapter we just created is not visible`),
Advice: "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system", Advice: "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system",
Issues: []int{3614}, Issues: []int{3614, 4222},
URL: "https://stackoverflow.com/questions/52277019/how-to-fix-vm-issue-with-minikube-start", URL: "https://stackoverflow.com/questions/52277019/how-to-fix-vm-issue-with-minikube-start",
}, },
"VBOX_KERNEL_MODULE_NOT_LOADED": { "VBOX_KERNEL_MODULE_NOT_LOADED": {
@ -80,10 +86,16 @@ var vmProblems = map[string]match{
Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver", Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver",
URL: "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver", URL: "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
}, },
"KVM2_NO_IP": { "KVM2_RESTART_NO_IP": {
Regexp: re(`Error starting stopped host: Machine didn't return an IP after 120 seconds`), 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.", Advice: "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.",
Issues: []int{3901, 3566, 3434}, Issues: []int{3901, 3434},
},
"KVM2_START_NO_IP": {
Regexp: re(`Error in driver during machine creation: Machine didn't return an IP after 120 seconds`),
Advice: "The KVM driver is not providing an IP address to the VM. Try checking your libvirt configuration and/or opening an issue",
URL: "https://fedoraproject.org/wiki/How_to_debug_Virtualization_problems#Networking",
Issues: []int{4249, 3566},
}, },
"KVM2_NETWORK_DEFINE_XML": { "KVM2_NETWORK_DEFINE_XML": {
Regexp: re(`not supported by the connection driver: virNetworkDefineXML`), Regexp: re(`not supported by the connection driver: virNetworkDefineXML`),
@ -91,10 +103,11 @@ var vmProblems = map[string]match{
URL: "https://forums.gentoo.org/viewtopic-t-981692-start-0.html", URL: "https://forums.gentoo.org/viewtopic-t-981692-start-0.html",
Issues: []int{4195}, Issues: []int{4195},
}, },
"VM_DOES_NOT_EXIST": { "KVM_UNAVAILABLE": {
Regexp: re(`Error getting state for host: machine does not exist`), Regexp: re(`invalid argument: could not find capabilities for domaintype=kvm`),
Advice: "Your system no longer knows about the VM previously created by minikube. Run 'minikube delete' to reset your local state.", Advice: "Your host does not support KVM virtualization. Ensure that qemu-kvm is installed, and run 'virt-host-validate' to debug the problem",
Issues: []int{3864}, URL: "http://mikko.repolainen.fi/documents/virtualization-with-kvm",
Issues: []int{2991},
}, },
"VM_BOOT_FAILED_HYPERV_ENABLED": { "VM_BOOT_FAILED_HYPERV_ENABLED": {
Regexp: re(`VirtualBox won't boot a 64bits VM when Hyper-V is activated`), Regexp: re(`VirtualBox won't boot a 64bits VM when Hyper-V is activated`),
@ -106,6 +119,21 @@ var vmProblems = map[string]match{
Advice: "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=<switch-name>` to `minikube start`", Advice: "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=<switch-name>` to `minikube start`",
URL: "https://docs.docker.com/machine/drivers/hyper-v/", 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",
Issues: []int{3594},
},
"OOM_KILL_SSH": {
Regexp: re(`Process exited with status 137 from signal KILL`),
Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
Issues: []int{1766},
},
"OOM_KILL_SCP": {
Regexp: re(`An existing connection was forcibly closed by the remote host`),
Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
Issues: []int{1766},
},
} }
// proxyDoc is the URL to proxy documentation // proxyDoc is the URL to proxy documentation
@ -132,10 +160,10 @@ var netProblems = map[string]match{
Issues: []int{3846}, Issues: []int{3846},
}, },
"DOWNLOAD_TLS_OVERSIZED": { "DOWNLOAD_TLS_OVERSIZED": {
Regexp: re(`failed to download.*tls: oversized record received with length`), Regexp: re(`tls: oversized record received with length`),
Advice: "A firewall is interfering with minikube's ability to make outgoing HTTPS requests. You may need to configure minikube to use a proxy.", Advice: "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.",
URL: proxyDoc, URL: proxyDoc,
Issues: []int{3857, 3759}, Issues: []int{3857, 3759, 4252},
}, },
"ISO_DOWNLOAD_FAILED": { "ISO_DOWNLOAD_FAILED": {
Regexp: re(`iso: failed to download`), Regexp: re(`iso: failed to download`),
@ -181,6 +209,11 @@ var deployProblems = map[string]match{
Regexp: re(`strconv.ParseUint: parsing "": invalid syntax`), Regexp: re(`strconv.ParseUint: parsing "": invalid syntax`),
Advice: "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'", Advice: "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'",
}, },
"APISERVER_TIMEOUT": {
Regexp: re(`wait: waiting for component=kube-apiserver: timed out waiting for the condition`),
Advice: "Run 'minikube delete'. If the problem persists, check your proxy or firewall configuration",
Issues: []int{4202, 3836, 4221},
},
} }
// osProblems are operating-system specific issues // osProblems are operating-system specific issues
@ -190,6 +223,12 @@ var osProblems = map[string]match{
Advice: "Run minikube from the C: drive.", Advice: "Run minikube from the C: drive.",
Issues: []int{1574}, Issues: []int{1574},
}, },
"SYSTEMCTL_EXIT_1": {
Regexp: re(`Failed to enable container runtime: .*sudo systemctl start docker: exit status 1`),
Advice: "If using the none driver, ensure that systemctl is installed",
URL: "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md",
Issues: []int{2704},
},
} }
// stateProblems are issues relating to local state // stateProblems are issues relating to local state

View File

@ -29,6 +29,8 @@ func TestFromError(t *testing.T) {
err string err string
}{ }{
{0, "", "", "this is just a lame error message with no matches."}, {0, "", "", "this is just a lame error message with no matches."},
{2991, "", "KVM_UNAVAILABLE", "Unable to start VM: create: Error creating machine: Error in driver during machine creation: creating domain: Error defining domain xml:\n\n: virError(Code=8, Domain=44, Message='invalid argument: could not find capabilities for domaintype=kvm ')"},
{3594, "", "HOST_CIDR_CONFLICT", "Error starting host: Error starting stopped host: Error setting up host only network on machine start: host-only cidr conflicts with the network address of a host interface."},
{3614, "", "VBOX_HOST_ADAPTER", "Error starting host: Error starting stopped host: Error setting up host only network on machine start: The host-only adapter we just created is not visible. This is a well known VirtualBox bug. You might want to uninstall it and reinstall at least version 5.0.12 that is is supposed to fix this issue"}, {3614, "", "VBOX_HOST_ADAPTER", "Error starting host: Error starting stopped host: Error setting up host only network on machine start: The host-only adapter we just created is not visible. This is a well known VirtualBox bug. You might want to uninstall it and reinstall at least version 5.0.12 that is is supposed to fix this issue"},
{3784, "", "VBOX_NOT_FOUND", "create: precreate: VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path"}, {3784, "", "VBOX_NOT_FOUND", "create: precreate: VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path"},
{3849, "", "IP_NOT_FOUND", "bootstrapper: Error creating new ssh host from driver: Error getting ssh host name for driver: IP not found"}, {3849, "", "IP_NOT_FOUND", "bootstrapper: Error creating new ssh host from driver: Error getting ssh host name for driver: IP not found"},
@ -38,6 +40,9 @@ VBoxManage.exe: error: Details: code E_FAIL (0x80004005), component MachineWrap,
{3922, "", "ISO_DOWNLOAD_FAILED", `unable to cache ISO: https://storage.googleapis.com/minikube/iso/minikube-v0.35.0.iso: failed to download: failed to download to temp file: download failed: 5 error(s) occurred: {3922, "", "ISO_DOWNLOAD_FAILED", `unable to cache ISO: https://storage.googleapis.com/minikube/iso/minikube-v0.35.0.iso: failed to download: failed to download to temp file: download failed: 5 error(s) occurred:
* Temporary download error: Get https://storage.googleapis.com/minikube/iso/minikube-v0.35.0.iso: dial tcp 216.58.207.144:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.`}, * Temporary download error: Get https://storage.googleapis.com/minikube/iso/minikube-v0.35.0.iso: dial tcp 216.58.207.144:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.`},
{4107, "darwin", "VBOX_BLOCKED", "Result Code: NS_ERROR_FAILURE (0x80004005)"}, {4107, "darwin", "VBOX_BLOCKED", "Result Code: NS_ERROR_FAILURE (0x80004005)"},
{4202, "", "APISERVER_TIMEOUT", "Error restarting cluster: wait: waiting for component=kube-apiserver: timed out waiting for the condition"},
{4252, "", "DOWNLOAD_TLS_OVERSIZED", "Failed to update cluster: downloading binaries: downloading kubeadm: Error downloading kubeadm v1.14.1: failed to download: failed to download to temp file: download failed: 5 error(s) occurred:\n\nTemporary download error: Get https://storage.googleapis.com/kubernetes-release/release/v1.14.1/bin/linux/amd64/kubeadm: proxyconnect tcp: tls: oversized record received with length 20527"},
{4222, "", "VBOX_HOST_ADAPTER", "Unable to start VM: create: creating: Error setting up host only network on machine start: The host-only adapter we just created is not visible. This is a well known VirtualBox bug. You might want to uninstall it and reinstall at least version 5.0.12 that is is supposed to fix this issue"},
} }
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.want, func(t *testing.T) { t.Run(tc.want, func(t *testing.T) {

View File

@ -29,11 +29,11 @@ import (
"github.com/pkg/browser" "github.com/pkg/browser"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/viper" "github.com/spf13/viper"
"k8s.io/api/core/v1" core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1" typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/cluster"
@ -45,7 +45,7 @@ import (
// K8sClient represents a kubernetes client // K8sClient represents a kubernetes client
type K8sClient interface { type K8sClient interface {
GetCoreClient() (corev1.CoreV1Interface, error) GetCoreClient() (typed_core.CoreV1Interface, error)
GetClientset(timeout time.Duration) (*kubernetes.Clientset, error) GetClientset(timeout time.Duration) (*kubernetes.Clientset, error)
} }
@ -60,12 +60,12 @@ func init() {
} }
// GetCoreClient returns a core client // GetCoreClient returns a core client
func (k *K8sClientGetter) GetCoreClient() (corev1.CoreV1Interface, error) { func (k *K8sClientGetter) GetCoreClient() (typed_core.CoreV1Interface, error) {
client, err := k.GetClientset(constants.DefaultK8sClientTimeout) client, err := k.GetClientset(constants.DefaultK8sClientTimeout)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting clientset") return nil, errors.Wrap(err, "getting clientset")
} }
return client.Core(), nil return client.CoreV1(), nil
} }
// GetClientset returns a clientset // GetClientset returns a clientset
@ -81,12 +81,12 @@ func (*K8sClientGetter) GetClientset(timeout time.Duration) (*kubernetes.Clients
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides) kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
clientConfig, err := kubeConfig.ClientConfig() clientConfig, err := kubeConfig.ClientConfig()
if err != nil { if err != nil {
return nil, fmt.Errorf("Error creating kubeConfig: %v", err) return nil, fmt.Errorf("kubeConfig: %v", err)
} }
clientConfig.Timeout = timeout clientConfig.Timeout = timeout
client, err := kubernetes.NewForConfig(clientConfig) client, err := kubernetes.NewForConfig(clientConfig)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()") return nil, errors.Wrap(err, "client from config")
} }
return client, nil return client, nil
@ -122,7 +122,7 @@ func GetServiceURLs(api libmachine.API, namespace string, t *template.Template)
serviceInterface := client.Services(namespace) serviceInterface := client.Services(namespace)
svcs, err := serviceInterface.List(metav1.ListOptions{}) svcs, err := serviceInterface.List(meta.ListOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -160,24 +160,24 @@ func GetServiceURLsForService(api libmachine.API, namespace, service string, t *
return printURLsForService(client, ip, service, namespace, t) return printURLsForService(client, ip, service, namespace, t)
} }
func printURLsForService(c corev1.CoreV1Interface, ip, service, namespace string, t *template.Template) ([]string, error) { func printURLsForService(c typed_core.CoreV1Interface, ip, service, namespace string, t *template.Template) ([]string, error) {
if t == nil { if t == nil {
return nil, errors.New("Error, attempted to generate service url with nil --format template") return nil, errors.New("Error, attempted to generate service url with nil --format template")
} }
s := c.Services(namespace) s := c.Services(namespace)
svc, err := s.Get(service, metav1.GetOptions{}) svc, err := s.Get(service, meta.GetOptions{})
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "service '%s' could not be found running", service) return nil, errors.Wrapf(err, "service '%s' could not be found running", service)
} }
e := c.Endpoints(namespace) e := c.Endpoints(namespace)
endpoints, err := e.Get(service, metav1.GetOptions{}) endpoints, err := e.Get(service, meta.GetOptions{})
m := make(map[int32]string) m := make(map[int32]string)
if err == nil && endpoints != nil && len(endpoints.Subsets) > 0 { if err == nil && endpoints != nil && len(endpoints.Subsets) > 0 {
for _, ept := range endpoints.Subsets { for _, ept := range endpoints.Subsets {
for _, p := range ept.Ports { for _, p := range ept.Ports {
m[int32(p.Port)] = p.Name m[p.Port] = p.Name
} }
} }
} }
@ -211,7 +211,7 @@ func CheckService(namespace string, service string) error {
return errors.Wrap(err, "Error getting kubernetes client") return errors.Wrap(err, "Error getting kubernetes client")
} }
svc, err := client.Services(namespace).Get(service, metav1.GetOptions{}) svc, err := client.Services(namespace).Get(service, meta.GetOptions{})
if err != nil { if err != nil {
return &util.RetriableError{ return &util.RetriableError{
Err: errors.Wrapf(err, "Error getting service %s", service), Err: errors.Wrapf(err, "Error getting service %s", service),
@ -258,30 +258,28 @@ func WaitAndMaybeOpenService(api libmachine.API, namespace string, service strin
console.OutLn(urlString) console.OutLn(urlString)
} else { } else {
console.OutStyle("celebrate", "Opening kubernetes service %s/%s in default browser...", namespace, service) console.OutStyle("celebrate", "Opening kubernetes service %s/%s in default browser...", namespace, service)
browser.OpenURL(urlString) if err := browser.OpenURL(urlString); err != nil {
console.Err("browser failed to open url: %v", err)
}
} }
} }
return nil return nil
} }
// GetServiceListByLabel returns a ServiceList by label // GetServiceListByLabel returns a ServiceList by label
func GetServiceListByLabel(namespace string, key string, value string) (*v1.ServiceList, error) { func GetServiceListByLabel(namespace string, key string, value string) (*core.ServiceList, error) {
client, err := K8s.GetCoreClient() client, err := K8s.GetCoreClient()
if err != nil { if err != nil {
return &v1.ServiceList{}, &util.RetriableError{Err: err} return &core.ServiceList{}, &util.RetriableError{Err: err}
} }
services := client.Services(namespace) return getServiceListFromServicesByLabel(client.Services(namespace), key, value)
if err != nil {
return &v1.ServiceList{}, &util.RetriableError{Err: err}
}
return getServiceListFromServicesByLabel(services, key, value)
} }
func getServiceListFromServicesByLabel(services corev1.ServiceInterface, key string, value string) (*v1.ServiceList, error) { func getServiceListFromServicesByLabel(services typed_core.ServiceInterface, key string, value string) (*core.ServiceList, error) {
selector := labels.SelectorFromSet(labels.Set(map[string]string{key: value})) selector := labels.SelectorFromSet(labels.Set(map[string]string{key: value}))
serviceList, err := services.List(metav1.ListOptions{LabelSelector: selector.String()}) serviceList, err := services.List(meta.ListOptions{LabelSelector: selector.String()})
if err != nil { if err != nil {
return &v1.ServiceList{}, &util.RetriableError{Err: err} return &core.ServiceList{}, &util.RetriableError{Err: err}
} }
return serviceList, nil return serviceList, nil
@ -294,11 +292,7 @@ func CreateSecret(namespace, name string, dataValues map[string]string, labels m
return &util.RetriableError{Err: err} return &util.RetriableError{Err: err}
} }
secrets := client.Secrets(namespace) secrets := client.Secrets(namespace)
if err != nil { secret, _ := secrets.Get(name, meta.GetOptions{})
return &util.RetriableError{Err: err}
}
secret, _ := secrets.Get(name, metav1.GetOptions{})
// Delete existing secret // Delete existing secret
if len(secret.Name) > 0 { if len(secret.Name) > 0 {
@ -315,13 +309,13 @@ func CreateSecret(namespace, name string, dataValues map[string]string, labels m
} }
// Create Secret // Create Secret
secretObj := &v1.Secret{ secretObj := &core.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: name, Name: name,
Labels: labels, Labels: labels,
}, },
Data: data, Data: data,
Type: v1.SecretTypeOpaque, Type: core.SecretTypeOpaque,
} }
_, err = secrets.Create(secretObj) _, err = secrets.Create(secretObj)
@ -340,11 +334,7 @@ func DeleteSecret(namespace, name string) error {
} }
secrets := client.Secrets(namespace) secrets := client.Secrets(namespace)
if err != nil { err = secrets.Delete(name, &meta.DeleteOptions{})
return &util.RetriableError{Err: err}
}
err = secrets.Delete(name, &metav1.DeleteOptions{})
if err != nil { if err != nil {
return &util.RetriableError{Err: err} return &util.RetriableError{Err: err}
} }

View File

@ -22,26 +22,27 @@ import (
"testing" "testing"
"text/template" "text/template"
"time"
"github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/host"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/api/core/v1" core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1" typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/kubernetes/typed/core/v1/fake" "k8s.io/client-go/kubernetes/typed/core/v1/fake"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/tests" "k8s.io/minikube/pkg/minikube/tests"
"time"
) )
type MockClientGetter struct { type MockClientGetter struct {
servicesMap map[string]corev1.ServiceInterface servicesMap map[string]typed_core.ServiceInterface
endpointsMap map[string]corev1.EndpointsInterface endpointsMap map[string]typed_core.EndpointsInterface
} }
func (m *MockClientGetter) GetCoreClient() (corev1.CoreV1Interface, error) { func (m *MockClientGetter) GetCoreClient() (typed_core.CoreV1Interface, error) {
return &MockCoreClient{ return &MockCoreClient{
servicesMap: m.servicesMap, servicesMap: m.servicesMap,
endpointsMap: m.endpointsMap, endpointsMap: m.endpointsMap,
@ -54,24 +55,24 @@ func (m *MockClientGetter) GetClientset(timeout time.Duration) (*kubernetes.Clie
type MockCoreClient struct { type MockCoreClient struct {
fake.FakeCoreV1 fake.FakeCoreV1
servicesMap map[string]corev1.ServiceInterface servicesMap map[string]typed_core.ServiceInterface
endpointsMap map[string]corev1.EndpointsInterface endpointsMap map[string]typed_core.EndpointsInterface
} }
var serviceNamespaces = map[string]corev1.ServiceInterface{ var serviceNamespaces = map[string]typed_core.ServiceInterface{
"default": defaultNamespaceServiceInterface, "default": defaultNamespaceServiceInterface,
} }
var defaultNamespaceServiceInterface = &MockServiceInterface{ var defaultNamespaceServiceInterface = &MockServiceInterface{
ServiceList: &v1.ServiceList{ ServiceList: &core.ServiceList{
Items: []v1.Service{ Items: []core.Service{
{ {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "mock-dashboard", Name: "mock-dashboard",
Namespace: "default", Namespace: "default",
}, },
Spec: v1.ServiceSpec{ Spec: core.ServiceSpec{
Ports: []v1.ServicePort{ Ports: []core.ServicePort{
{ {
NodePort: int32(1111), NodePort: int32(1111),
TargetPort: intstr.IntOrString{ TargetPort: intstr.IntOrString{
@ -88,44 +89,44 @@ var defaultNamespaceServiceInterface = &MockServiceInterface{
}, },
}, },
{ {
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "mock-dashboard-no-ports", Name: "mock-dashboard-no-ports",
Namespace: "default", Namespace: "default",
}, },
Spec: v1.ServiceSpec{ Spec: core.ServiceSpec{
Ports: []v1.ServicePort{}, Ports: []core.ServicePort{},
}, },
}, },
}, },
}, },
} }
var endpointNamespaces = map[string]corev1.EndpointsInterface{ var endpointNamespaces = map[string]typed_core.EndpointsInterface{
"default": defaultNamespaceEndpointInterface, "default": defaultNamespaceEndpointInterface,
} }
var defaultNamespaceEndpointInterface = &MockEndpointsInterface{} var defaultNamespaceEndpointInterface = &MockEndpointsInterface{}
func (m *MockCoreClient) Endpoints(namespace string) corev1.EndpointsInterface { func (m *MockCoreClient) Endpoints(namespace string) typed_core.EndpointsInterface {
return m.endpointsMap[namespace] return m.endpointsMap[namespace]
} }
func (m *MockCoreClient) Services(namespace string) corev1.ServiceInterface { func (m *MockCoreClient) Services(namespace string) typed_core.ServiceInterface {
return m.servicesMap[namespace] return m.servicesMap[namespace]
} }
type MockEndpointsInterface struct { type MockEndpointsInterface struct {
fake.FakeEndpoints fake.FakeEndpoints
Endpoints *v1.Endpoints Endpoints *core.Endpoints
} }
var endpointMap = map[string]*v1.Endpoints{ var endpointMap = map[string]*core.Endpoints{
"no-subsets": {}, "no-subsets": {},
"not-ready": { "not-ready": {
Subsets: []v1.EndpointSubset{ Subsets: []core.EndpointSubset{
{ {
Addresses: []v1.EndpointAddress{}, Addresses: []core.EndpointAddress{},
NotReadyAddresses: []v1.EndpointAddress{ NotReadyAddresses: []core.EndpointAddress{
{IP: "1.1.1.1"}, {IP: "1.1.1.1"},
{IP: "2.2.2.2"}, {IP: "2.2.2.2"},
}, },
@ -133,21 +134,21 @@ var endpointMap = map[string]*v1.Endpoints{
}, },
}, },
"one-ready": { "one-ready": {
Subsets: []v1.EndpointSubset{ Subsets: []core.EndpointSubset{
{ {
Addresses: []v1.EndpointAddress{ Addresses: []core.EndpointAddress{
{IP: "1.1.1.1"}, {IP: "1.1.1.1"},
}, },
NotReadyAddresses: []v1.EndpointAddress{ NotReadyAddresses: []core.EndpointAddress{
{IP: "2.2.2.2"}, {IP: "2.2.2.2"},
}, },
}, },
}, },
}, },
"mock-dashboard": { "mock-dashboard": {
Subsets: []v1.EndpointSubset{ Subsets: []core.EndpointSubset{
{ {
Ports: []v1.EndpointPort{ Ports: []core.EndpointPort{
{ {
Name: "port1", Name: "port1",
Port: int32(11111), Port: int32(11111),
@ -162,7 +163,7 @@ var endpointMap = map[string]*v1.Endpoints{
}, },
} }
func (e MockEndpointsInterface) Get(name string, _ metav1.GetOptions) (*v1.Endpoints, error) { func (e MockEndpointsInterface) Get(name string, _ meta.GetOptions) (*core.Endpoints, error) {
endpoint, ok := endpointMap[name] endpoint, ok := endpointMap[name]
if !ok { if !ok {
return nil, errors.New("Endpoint not found") return nil, errors.New("Endpoint not found")
@ -172,12 +173,12 @@ func (e MockEndpointsInterface) Get(name string, _ metav1.GetOptions) (*v1.Endpo
type MockServiceInterface struct { type MockServiceInterface struct {
fake.FakeServices fake.FakeServices
ServiceList *v1.ServiceList ServiceList *core.ServiceList
} }
func (s MockServiceInterface) List(opts metav1.ListOptions) (*v1.ServiceList, error) { func (s MockServiceInterface) List(opts meta.ListOptions) (*core.ServiceList, error) {
serviceList := &v1.ServiceList{ serviceList := &core.ServiceList{
Items: []v1.Service{}, Items: []core.Service{},
} }
if opts.LabelSelector != "" { if opts.LabelSelector != "" {
keyValArr := strings.Split(opts.LabelSelector, "=") keyValArr := strings.Split(opts.LabelSelector, "=")
@ -194,7 +195,7 @@ func (s MockServiceInterface) List(opts metav1.ListOptions) (*v1.ServiceList, er
return s.ServiceList, nil return s.ServiceList, nil
} }
func (s MockServiceInterface) Get(name string, _ metav1.GetOptions) (*v1.Service, error) { func (s MockServiceInterface) Get(name string, _ meta.GetOptions) (*core.Service, error) {
for _, svc := range s.ServiceList.Items { for _, svc := range s.ServiceList.Items {
if svc.ObjectMeta.Name == name { if svc.ObjectMeta.Name == name {
return &svc, nil return &svc, nil
@ -205,10 +206,10 @@ func (s MockServiceInterface) Get(name string, _ metav1.GetOptions) (*v1.Service
} }
func TestGetServiceListFromServicesByLabel(t *testing.T) { func TestGetServiceListFromServicesByLabel(t *testing.T) {
serviceList := &v1.ServiceList{ serviceList := &core.ServiceList{
Items: []v1.Service{ Items: []core.Service{
{ {
Spec: v1.ServiceSpec{ Spec: core.ServiceSpec{
Selector: map[string]string{ Selector: map[string]string{
"foo": "bar", "foo": "bar",
}, },

View File

@ -44,10 +44,10 @@ func TestNewSSHClient(t *testing.T) {
cmd := "foo" cmd := "foo"
sess, err := c.NewSession() sess, err := c.NewSession()
defer sess.Close()
if err != nil { if err != nil {
t.Fatal("Error creating new session for ssh client") t.Fatal("Error creating new session for ssh client")
} }
defer sess.Close()
if err := sess.Run(cmd); err != nil { if err := sess.Run(cmd); err != nil {
t.Fatalf("Error running command: %s", cmd) t.Fatalf("Error running command: %s", cmd)

View File

@ -20,7 +20,7 @@ import (
"strconv" "strconv"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/api/storage/v1" v1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
@ -31,7 +31,7 @@ func annotateDefaultStorageClass(client *kubernetes.Clientset, class *v1.Storage
isDefault := strconv.FormatBool(enable) isDefault := strconv.FormatBool(enable)
metav1.SetMetaDataAnnotation(&class.ObjectMeta, "storageclass.beta.kubernetes.io/is-default-class", isDefault) metav1.SetMetaDataAnnotation(&class.ObjectMeta, "storageclass.beta.kubernetes.io/is-default-class", isDefault)
_, err := client.Storage().StorageClasses().Update(class) _, err := client.StorageV1().StorageClasses().Update(class)
return err return err
} }
@ -50,7 +50,7 @@ func DisableDefaultStorageClass(class string) error {
return errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()") return errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()")
} }
sc, err := client.Storage().StorageClasses().Get(class, metav1.GetOptions{}) sc, err := client.StorageV1().StorageClasses().Get(class, metav1.GetOptions{})
if err != nil { if err != nil {
return errors.Wrapf(err, "Error getting storage class %s", class) return errors.Wrapf(err, "Error getting storage class %s", class)
} }
@ -77,7 +77,7 @@ func SetDefaultStorageClass(name string) error {
return errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()") return errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()")
} }
scList, err := client.Storage().StorageClasses().List(metav1.ListOptions{}) scList, err := client.StorageV1().StorageClasses().List(metav1.ListOptions{})
if err != nil { if err != nil {
return errors.Wrap(err, "Error listing StorageClasses") return errors.Wrap(err, "Error listing StorageClasses")
} }

View File

@ -110,12 +110,16 @@ func (s *SSHServer) Start() (int, error) {
glog.Infoln("Got Req: ", req.Type) glog.Infoln("Got Req: ", req.Type)
// Store anything that comes in over stdin. // Store anything that comes in over stdin.
go func() { go func() {
io.Copy(s.Transfers, channel) if _, err := io.Copy(s.Transfers, channel); err != nil {
panic(fmt.Sprintf("copy failed: %v", err))
}
channel.Close() channel.Close()
}() }()
switch req.Type { switch req.Type {
case "exec": case "exec":
req.Reply(true, nil) if err := req.Reply(true, nil); err != nil {
panic(fmt.Sprintf("reply failed: %v", err))
}
// Note: string(req.Payload) adds additional characters to start of input. // Note: string(req.Payload) adds additional characters to start of input.
var cmd execRequest var cmd execRequest
@ -127,14 +131,26 @@ func (s *SSHServer) Start() (int, error) {
// Write specified command output as mocked ssh output // Write specified command output as mocked ssh output
if val, err := s.GetCommandToOutput(cmd.Command); err == nil { if val, err := s.GetCommandToOutput(cmd.Command); err == nil {
channel.Write([]byte(val)) if _, err := channel.Write([]byte(val)); err != nil {
glog.Errorf("Write failed: %v", err)
return
}
}
if _, err := channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0}); err != nil {
glog.Errorf("SendRequest failed: %v", err)
return
} }
channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0})
case "pty-req": case "pty-req":
req.Reply(true, nil) if err := req.Reply(true, nil); err != nil {
glog.Errorf("Reply failed: %v", err)
return
}
channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) if _, err := channel.SendRequest("exit-status", false, []byte{0, 0, 0, 0}); err != nil {
glog.Errorf("SendRequest failed: %v", err)
return
}
} }
} }
} }

View File

@ -26,6 +26,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/util"
) )
type clusterInspector struct { type clusterInspector struct {
@ -93,9 +94,14 @@ func getRoute(host *host.Host, clusterConfig config.Config) (*Route, error) {
if ip == nil { if ip == nil {
return nil, fmt.Errorf("invalid IP for host %s", hostDriverIP) return nil, fmt.Errorf("invalid IP for host %s", hostDriverIP)
} }
dnsIP, err := util.GetDNSIP(ipNet.String())
if err != nil {
return nil, err
}
return &Route{ return &Route{
Gateway: ip, Gateway: ip,
DestCIDR: ipNet, DestCIDR: ipNet,
ClusterDomain: clusterConfig.KubernetesConfig.DNSDomain,
ClusterDNSIP: dnsIP,
}, nil }, nil
} }

View File

@ -19,6 +19,8 @@ package tunnel
import ( import (
"testing" "testing"
"k8s.io/minikube/pkg/util"
"net" "net"
"reflect" "reflect"
"strings" "strings"
@ -78,10 +80,15 @@ func TestMinikubeCheckReturnsHostInformation(t *testing.T) {
ip := net.ParseIP("1.2.3.4") ip := net.ParseIP("1.2.3.4")
_, ipNet, _ := net.ParseCIDR("96.0.0.0/12") _, ipNet, _ := net.ParseCIDR("96.0.0.0/12")
dnsIP, err := util.GetDNSIP(ipNet.String())
if err != nil {
t.Errorf("getdnsIP: %v", err)
}
expectedRoute := &Route{ expectedRoute := &Route{
Gateway: ip, Gateway: ip,
DestCIDR: ipNet, DestCIDR: ipNet,
ClusterDNSIP: dnsIP,
} }
if s != Running { if s != Running {

View File

@ -20,10 +20,10 @@ import (
"fmt" "fmt"
"github.com/golang/glog" "github.com/golang/glog"
core_v1 "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
k8s_types "k8s.io/apimachinery/pkg/types" types "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/typed/core/v1" typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
) )
@ -39,26 +39,22 @@ type patchConverter interface {
//loadBalancerEmulator is the main struct for emulating the loadbalancer behavior. it sets the ingress to the cluster IP //loadBalancerEmulator is the main struct for emulating the loadbalancer behavior. it sets the ingress to the cluster IP
type loadBalancerEmulator struct { type loadBalancerEmulator struct {
coreV1Client v1.CoreV1Interface coreV1Client typed_core.CoreV1Interface
requestSender requestSender requestSender requestSender
patchConverter patchConverter patchConverter patchConverter
} }
func (l *loadBalancerEmulator) PatchServices() ([]string, error) { func (l *loadBalancerEmulator) PatchServices() ([]string, error) {
return l.applyOnLBServices(func(restClient rest.Interface, svc core_v1.Service) ([]byte, error) { return l.applyOnLBServices(l.updateService)
return l.updateService(restClient, svc)
})
} }
func (l *loadBalancerEmulator) Cleanup() ([]string, error) { func (l *loadBalancerEmulator) Cleanup() ([]string, error) {
return l.applyOnLBServices(func(restClient rest.Interface, svc core_v1.Service) ([]byte, error) { return l.applyOnLBServices(l.cleanupService)
return l.cleanupService(restClient, svc)
})
} }
func (l *loadBalancerEmulator) applyOnLBServices(action func(restClient rest.Interface, svc core_v1.Service) ([]byte, error)) ([]string, error) { func (l *loadBalancerEmulator) applyOnLBServices(action func(restClient rest.Interface, svc core.Service) ([]byte, error)) ([]string, error) {
services := l.coreV1Client.Services("") services := l.coreV1Client.Services("")
serviceList, err := services.List(metav1.ListOptions{}) serviceList, err := services.List(meta.ListOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -83,7 +79,7 @@ func (l *loadBalancerEmulator) applyOnLBServices(action func(restClient rest.Int
} }
return managedServices, nil return managedServices, nil
} }
func (l *loadBalancerEmulator) updateService(restClient rest.Interface, svc core_v1.Service) ([]byte, error) { func (l *loadBalancerEmulator) updateService(restClient rest.Interface, svc core.Service) ([]byte, error) {
clusterIP := svc.Spec.ClusterIP clusterIP := svc.Spec.ClusterIP
ingresses := svc.Status.LoadBalancer.Ingress ingresses := svc.Status.LoadBalancer.Ingress
if len(ingresses) == 1 && ingresses[0].IP == clusterIP { if len(ingresses) == 1 && ingresses[0].IP == clusterIP {
@ -92,7 +88,7 @@ func (l *loadBalancerEmulator) updateService(restClient rest.Interface, svc core
glog.V(3).Infof("[%s] setting ClusterIP as the LoadBalancer Ingress", svc.Name) glog.V(3).Infof("[%s] setting ClusterIP as the LoadBalancer Ingress", svc.Name)
jsonPatch := fmt.Sprintf(`[{"op": "add", "path": "/status/loadBalancer/ingress", "value": [ { "ip": "%s" } ] }]`, clusterIP) jsonPatch := fmt.Sprintf(`[{"op": "add", "path": "/status/loadBalancer/ingress", "value": [ { "ip": "%s" } ] }]`, clusterIP)
patch := &Patch{ patch := &Patch{
Type: k8s_types.JSONPatchType, Type: types.JSONPatchType,
ResourceName: svc.Name, ResourceName: svc.Name,
NameSpaceSet: true, NameSpaceSet: true,
NameSpace: svc.Namespace, NameSpace: svc.Namespace,
@ -110,7 +106,7 @@ func (l *loadBalancerEmulator) updateService(restClient rest.Interface, svc core
return result, err return result, err
} }
func (l *loadBalancerEmulator) cleanupService(restClient rest.Interface, svc core_v1.Service) ([]byte, error) { func (l *loadBalancerEmulator) cleanupService(restClient rest.Interface, svc core.Service) ([]byte, error) {
ingresses := svc.Status.LoadBalancer.Ingress ingresses := svc.Status.LoadBalancer.Ingress
if len(ingresses) == 0 { if len(ingresses) == 0 {
return nil, nil return nil, nil
@ -118,7 +114,7 @@ func (l *loadBalancerEmulator) cleanupService(restClient rest.Interface, svc cor
glog.V(3).Infof("[%s] cleanup: unset load balancer ingress", svc.Name) glog.V(3).Infof("[%s] cleanup: unset load balancer ingress", svc.Name)
jsonPatch := `[{"op": "remove", "path": "/status/loadBalancer/ingress" }]` jsonPatch := `[{"op": "remove", "path": "/status/loadBalancer/ingress" }]`
patch := &Patch{ patch := &Patch{
Type: k8s_types.JSONPatchType, Type: types.JSONPatchType,
ResourceName: svc.Name, ResourceName: svc.Name,
NameSpaceSet: true, NameSpaceSet: true,
NameSpace: svc.Namespace, NameSpace: svc.Namespace,
@ -133,7 +129,7 @@ func (l *loadBalancerEmulator) cleanupService(restClient rest.Interface, svc cor
} }
func newLoadBalancerEmulator(corev1Client v1.CoreV1Interface) loadBalancerEmulator { func newLoadBalancerEmulator(corev1Client typed_core.CoreV1Interface) loadBalancerEmulator {
return loadBalancerEmulator{ return loadBalancerEmulator{
coreV1Client: corev1Client, coreV1Client: corev1Client,
requestSender: &defaultRequestSender{}, requestSender: &defaultRequestSender{},

View File

@ -21,20 +21,20 @@ import (
"reflect" "reflect"
apiV1 "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/typed/core/v1" typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/kubernetes/typed/core/v1/fake" fake "k8s.io/client-go/kubernetes/typed/core/v1/fake"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
) )
type stubCoreClient struct { type stubCoreClient struct {
fake.FakeCoreV1 fake.FakeCoreV1
servicesList *apiV1.ServiceList servicesList *core.ServiceList
restClient *rest.RESTClient restClient *rest.RESTClient
} }
func (c *stubCoreClient) Services(namespace string) v1.ServiceInterface { func (c *stubCoreClient) Services(namespace string) typed_core.ServiceInterface {
return &stubServices{ return &stubServices{
fake.FakeServices{Fake: &c.FakeCoreV1}, fake.FakeServices{Fake: &c.FakeCoreV1},
c.servicesList, c.servicesList,
@ -47,17 +47,17 @@ func (c *stubCoreClient) RESTClient() rest.Interface {
type stubServices struct { type stubServices struct {
fake.FakeServices fake.FakeServices
servicesList *apiV1.ServiceList servicesList *core.ServiceList
} }
func (s *stubServices) List(opts metaV1.ListOptions) (*apiV1.ServiceList, error) { func (s *stubServices) List(opts meta.ListOptions) (*core.ServiceList, error) {
return s.servicesList, nil return s.servicesList, nil
} }
func newStubCoreClient(servicesList *apiV1.ServiceList) *stubCoreClient { func newStubCoreClient(servicesList *core.ServiceList) *stubCoreClient {
if servicesList == nil { if servicesList == nil {
servicesList = &apiV1.ServiceList{ servicesList = &core.ServiceList{
Items: []apiV1.Service{}} Items: []core.Service{}}
} }
return &stubCoreClient{ return &stubCoreClient{
servicesList: servicesList, servicesList: servicesList,
@ -84,8 +84,8 @@ func (r *recordingPatchConverter) convert(restClient rest.Interface, patch *Patc
} }
func TestEmptyListOfServicesDoesNothing(t *testing.T) { func TestEmptyListOfServicesDoesNothing(t *testing.T) {
client := newStubCoreClient(&apiV1.ServiceList{ client := newStubCoreClient(&core.ServiceList{
Items: []apiV1.Service{}}) Items: []core.Service{}})
patcher := newLoadBalancerEmulator(client) patcher := newLoadBalancerEmulator(client)
@ -98,15 +98,15 @@ func TestEmptyListOfServicesDoesNothing(t *testing.T) {
} }
func TestServicesWithNoLoadbalancerType(t *testing.T) { func TestServicesWithNoLoadbalancerType(t *testing.T) {
client := newStubCoreClient(&apiV1.ServiceList{ client := newStubCoreClient(&core.ServiceList{
Items: []apiV1.Service{ Items: []core.Service{
{ {
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "ClusterIP", Type: "ClusterIP",
}, },
}, },
{ {
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "NodeIP", Type: "NodeIP",
}, },
}, },
@ -124,20 +124,20 @@ func TestServicesWithNoLoadbalancerType(t *testing.T) {
} }
func TestServicesWithLoadbalancerType(t *testing.T) { func TestServicesWithLoadbalancerType(t *testing.T) {
client := newStubCoreClient(&apiV1.ServiceList{ client := newStubCoreClient(&core.ServiceList{
Items: []apiV1.Service{ Items: []core.Service{
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc1-up-to-date", Name: "svc1-up-to-date",
Namespace: "ns1", Namespace: "ns1",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "LoadBalancer", Type: "LoadBalancer",
ClusterIP: "10.96.0.3", ClusterIP: "10.96.0.3",
}, },
Status: apiV1.ServiceStatus{ Status: core.ServiceStatus{
LoadBalancer: apiV1.LoadBalancerStatus{ LoadBalancer: core.LoadBalancerStatus{
Ingress: []apiV1.LoadBalancerIngress{ Ingress: []core.LoadBalancerIngress{
{ {
IP: "10.96.0.3", IP: "10.96.0.3",
}, },
@ -146,17 +146,17 @@ func TestServicesWithLoadbalancerType(t *testing.T) {
}, },
}, },
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc2-out-of-date", Name: "svc2-out-of-date",
Namespace: "ns2", Namespace: "ns2",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "LoadBalancer", Type: "LoadBalancer",
ClusterIP: "10.96.0.4", ClusterIP: "10.96.0.4",
}, },
Status: apiV1.ServiceStatus{ Status: core.ServiceStatus{
LoadBalancer: apiV1.LoadBalancerStatus{ LoadBalancer: core.LoadBalancerStatus{
Ingress: []apiV1.LoadBalancerIngress{ Ingress: []core.LoadBalancerIngress{
{ {
IP: "10.96.0.5", IP: "10.96.0.5",
}, },
@ -165,25 +165,25 @@ func TestServicesWithLoadbalancerType(t *testing.T) {
}, },
}, },
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc3-empty-ingress", Name: "svc3-empty-ingress",
Namespace: "ns3", Namespace: "ns3",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "LoadBalancer", Type: "LoadBalancer",
ClusterIP: "10.96.0.2", ClusterIP: "10.96.0.2",
}, },
Status: apiV1.ServiceStatus{ Status: core.ServiceStatus{
LoadBalancer: apiV1.LoadBalancerStatus{ LoadBalancer: core.LoadBalancerStatus{
Ingress: []apiV1.LoadBalancerIngress{}, Ingress: []core.LoadBalancerIngress{},
}, },
}, },
}, },
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc4-not-lb", Name: "svc4-not-lb",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "NodeIP", Type: "NodeIP",
}, },
}, },
@ -259,20 +259,20 @@ func TestCleanupPatchedIPs(t *testing.T) {
}, },
} }
client := newStubCoreClient(&apiV1.ServiceList{ client := newStubCoreClient(&core.ServiceList{
Items: []apiV1.Service{ Items: []core.Service{
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc1-up-to-date", Name: "svc1-up-to-date",
Namespace: "ns1", Namespace: "ns1",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "LoadBalancer", Type: "LoadBalancer",
ClusterIP: "10.96.0.3", ClusterIP: "10.96.0.3",
}, },
Status: apiV1.ServiceStatus{ Status: core.ServiceStatus{
LoadBalancer: apiV1.LoadBalancerStatus{ LoadBalancer: core.LoadBalancerStatus{
Ingress: []apiV1.LoadBalancerIngress{ Ingress: []core.LoadBalancerIngress{
{ {
IP: "10.96.0.3", IP: "10.96.0.3",
}, },
@ -281,17 +281,17 @@ func TestCleanupPatchedIPs(t *testing.T) {
}, },
}, },
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc2-out-of-date", Name: "svc2-out-of-date",
Namespace: "ns2", Namespace: "ns2",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "LoadBalancer", Type: "LoadBalancer",
ClusterIP: "10.96.0.4", ClusterIP: "10.96.0.4",
}, },
Status: apiV1.ServiceStatus{ Status: core.ServiceStatus{
LoadBalancer: apiV1.LoadBalancerStatus{ LoadBalancer: core.LoadBalancerStatus{
Ingress: []apiV1.LoadBalancerIngress{ Ingress: []core.LoadBalancerIngress{
{ {
IP: "10.96.0.5", IP: "10.96.0.5",
}, },
@ -300,25 +300,25 @@ func TestCleanupPatchedIPs(t *testing.T) {
}, },
}, },
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc3-empty-ingress", Name: "svc3-empty-ingress",
Namespace: "ns3", Namespace: "ns3",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "LoadBalancer", Type: "LoadBalancer",
ClusterIP: "10.96.0.2", ClusterIP: "10.96.0.2",
}, },
Status: apiV1.ServiceStatus{ Status: core.ServiceStatus{
LoadBalancer: apiV1.LoadBalancerStatus{ LoadBalancer: core.LoadBalancerStatus{
Ingress: []apiV1.LoadBalancerIngress{}, Ingress: []core.LoadBalancerIngress{},
}, },
}, },
}, },
{ {
ObjectMeta: metaV1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: "svc4-not-lb", Name: "svc4-not-lb",
}, },
Spec: apiV1.ServiceSpec{ Spec: core.ServiceSpec{
Type: "NodeIP", Type: "NodeIP",
}, },
}, },

View File

@ -76,6 +76,7 @@ func (t *routingTable) Check(route *Route) (exists bool, conflict string, overla
exists = false exists = false
overlaps = []string{} overlaps = []string{}
for _, tableLine := range *t { for _, tableLine := range *t {
if route.Equal(tableLine.route) { if route.Equal(tableLine.route) {
exists = true exists = true
} else if route.DestCIDR.String() == tableLine.route.DestCIDR.String() && } else if route.DestCIDR.String() == tableLine.route.DestCIDR.String() &&

View File

@ -18,7 +18,9 @@ package tunnel
import ( import (
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os"
"os/exec" "os/exec"
"regexp" "regexp"
"strings" "strings"
@ -34,6 +36,9 @@ func (router *osRouter) EnsureRouteIsAdded(route *Route) error {
if exists { if exists {
return nil return nil
} }
if err := writeResolverFile(route); err != nil {
return fmt.Errorf("could not write /etc/resolver/{cluster_domain} file: %s", err)
}
serviceCIDR := route.DestCIDR.String() serviceCIDR := route.DestCIDR.String()
gatewayIP := route.Gateway.String() gatewayIP := route.Gateway.String()
@ -162,5 +167,37 @@ func (router *osRouter) Cleanup(route *Route) error {
if !re.MatchString(message) { if !re.MatchString(message) {
return fmt.Errorf("error deleting route: %s, %d", message, len(strings.Split(message, "\n"))) return fmt.Errorf("error deleting route: %s, %d", message, len(strings.Split(message, "\n")))
} }
// idempotent removal of cluster domain dns
resolverFile := fmt.Sprintf("/etc/resolver/%s", route.ClusterDomain)
command = exec.Command("sudo", "rm", "-f", resolverFile)
if err := command.Run(); err != nil {
return fmt.Errorf("could not remove %s: %s", resolverFile, err)
}
return nil
}
func writeResolverFile(route *Route) error {
resolverFile := "/etc/resolver/" + route.ClusterDomain
content := fmt.Sprintf("nameserver %s\nsearch_order 1\n", route.ClusterDNSIP)
// write resolver content into tmpFile, then copy it to /etc/resolver/clusterDomain
tmpFile, err := ioutil.TempFile("", "minikube-tunnel-resolver-")
if err != nil {
return err
}
defer os.Remove(tmpFile.Name())
if _, err = tmpFile.WriteString(content); err != nil {
return err
}
if err = tmpFile.Close(); err != nil {
return err
}
command := exec.Command("sudo", "mkdir", "-p", "/etc/resolver")
if err := command.Run(); err != nil {
return err
}
command = exec.Command("sudo", "cp", "-f", tmpFile.Name(), resolverFile)
if err := command.Run(); err != nil {
return err
}
return nil return nil
} }

View File

@ -35,9 +35,14 @@ func TestDarwinRouteFailsOnConflictIntegrationTest(t *testing.T) {
IP: net.IPv4(10, 96, 0, 0), IP: net.IPv4(10, 96, 0, 0),
Mask: net.IPv4Mask(255, 240, 0, 0), Mask: net.IPv4Mask(255, 240, 0, 0),
}, },
ClusterDomain: "cluster.local",
ClusterDNSIP: net.IPv4(10, 96, 0, 10),
} }
conflictingCfg := *cfg
conflictingCfg.Gateway = net.IPv4(127, 0, 0, 2)
addRoute(t, "10.96.0.0/12", "127.0.0.2") addRoute(t, &conflictingCfg)
defer cleanRoute(t, &conflictingCfg)
err := (&osRouter{}).EnsureRouteIsAdded(cfg) err := (&osRouter{}).EnsureRouteIsAdded(cfg)
if err == nil { if err == nil {
t.Errorf("add should have error, but it is nil") t.Errorf("add should have error, but it is nil")
@ -51,9 +56,11 @@ func TestDarwinRouteIdempotentIntegrationTest(t *testing.T) {
IP: net.IPv4(10, 96, 0, 0), IP: net.IPv4(10, 96, 0, 0),
Mask: net.IPv4Mask(255, 240, 0, 0), Mask: net.IPv4Mask(255, 240, 0, 0),
}, },
ClusterDomain: "cluster.local",
ClusterDNSIP: net.IPv4(10, 96, 0, 10),
} }
cleanRoute(t, "10.96.0.0/12") cleanRoute(t, cfg)
err := (&osRouter{}).EnsureRouteIsAdded(cfg) err := (&osRouter{}).EnsureRouteIsAdded(cfg)
if err != nil { if err != nil {
t.Errorf("add error: %s", err) t.Errorf("add error: %s", err)
@ -64,7 +71,7 @@ func TestDarwinRouteIdempotentIntegrationTest(t *testing.T) {
t.Errorf("add error: %s", err) t.Errorf("add error: %s", err)
} }
cleanRoute(t, "10.96.0.0/12") cleanRoute(t, cfg)
} }
func TestDarwinRouteCleanupIdempontentIntegrationTest(t *testing.T) { func TestDarwinRouteCleanupIdempontentIntegrationTest(t *testing.T) {
@ -75,10 +82,12 @@ func TestDarwinRouteCleanupIdempontentIntegrationTest(t *testing.T) {
IP: net.IPv4(10, 96, 0, 0), IP: net.IPv4(10, 96, 0, 0),
Mask: net.IPv4Mask(255, 240, 0, 0), Mask: net.IPv4Mask(255, 240, 0, 0),
}, },
ClusterDomain: "cluster.local",
ClusterDNSIP: net.IPv4(10, 96, 0, 10),
} }
cleanRoute(t, "10.96.0.0/12") cleanRoute(t, cfg)
addRoute(t, "10.96.0.0/12", "192.168.1.1") addRoute(t, cfg)
err := (&osRouter{}).Cleanup(cfg) err := (&osRouter{}).Cleanup(cfg)
if err != nil { if err != nil {
t.Errorf("cleanup failed with %s", err) t.Errorf("cleanup failed with %s", err)
@ -89,20 +98,32 @@ func TestDarwinRouteCleanupIdempontentIntegrationTest(t *testing.T) {
} }
} }
func addRoute(t *testing.T, cidr string, gw string) { func addRoute(t *testing.T, r *Route) {
cidr := r.DestCIDR.String()
gw := r.Gateway.String()
command := exec.Command("sudo", "route", "-n", "add", cidr, gw) command := exec.Command("sudo", "route", "-n", "add", cidr, gw)
_, err := command.CombinedOutput() _, err := command.CombinedOutput()
if err != nil { if err != nil {
t.Logf("add route error (should be ok): %s", err) t.Logf("add route error (should be ok): %s", err)
} }
err = writeResolverFile(r)
if err != nil {
t.Logf("add route DNS resolver error (should be ok): %s", err)
}
} }
func cleanRoute(t *testing.T, cidr string) { func cleanRoute(t *testing.T, r *Route) {
cidr := r.DestCIDR.String()
command := exec.Command("sudo", "route", "-n", "delete", cidr) command := exec.Command("sudo", "route", "-n", "delete", cidr)
_, err := command.CombinedOutput() _, err := command.CombinedOutput()
if err != nil { if err != nil {
t.Logf("cleanup error (should be ok): %s", err) t.Logf("cleanup error (should be ok): %s", err)
} }
command = exec.Command("sudo", "rm", "-f", fmt.Sprintf("/etc/resolver/%s", r.ClusterDomain))
_, err = command.CombinedOutput()
if err != nil {
t.Logf("cleanup DNS resolver error (should be ok): %s", err)
}
} }
func TestCIDRPadding(t *testing.T) { func TestCIDRPadding(t *testing.T) {

View File

@ -20,6 +20,8 @@ import (
"net" "net"
"reflect" "reflect"
"testing" "testing"
"k8s.io/minikube/pkg/util"
) )
func TestRoutingTable(t *testing.T) { func TestRoutingTable(t *testing.T) {
@ -130,10 +132,12 @@ got
func unsafeParseRoute(gatewayIP string, destCIDR string) *Route { func unsafeParseRoute(gatewayIP string, destCIDR string) *Route {
ip := net.ParseIP(gatewayIP) ip := net.ParseIP(gatewayIP)
_, ipNet, _ := net.ParseCIDR(destCIDR) _, ipNet, _ := net.ParseCIDR(destCIDR)
dnsIP, _ := util.GetDNSIP(ipNet.String())
expectedRoute := &Route{ expectedRoute := &Route{
Gateway: ip, Gateway: ip,
DestCIDR: ipNet, DestCIDR: ipNet,
ClusterDNSIP: dnsIP,
} }
return expectedRoute return expectedRoute
} }

View File

@ -27,7 +27,7 @@ import (
"github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/host"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/client-go/kubernetes/typed/core/v1" typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
) )
@ -43,10 +43,7 @@ func errorTunnelAlreadyExists(id *ID) error {
return fmt.Errorf("there is already a running tunnel for this machine: %s", id) return fmt.Errorf("there is already a running tunnel for this machine: %s", id)
} }
func newTunnel(machineName string, func newTunnel(machineName string, machineAPI libmachine.API, configLoader config.Loader, v1Core typed_core.CoreV1Interface, registry *persistentRegistry, router router) (*tunnel, error) {
machineAPI libmachine.API,
configLoader config.Loader,
v1Core v1.CoreV1Interface, registry *persistentRegistry, router router) (*tunnel, error) {
ci := &clusterInspector{ ci := &clusterInspector{
machineName: machineName, machineName: machineName,
machineAPI: machineAPI, machineAPI: machineAPI,
@ -154,7 +151,7 @@ func setupRoute(t *tunnel, h *host.Host) {
if h.DriverName == "hyperkit" { if h.DriverName == "hyperkit" {
//the virtio-net interface acts up with ip tunnels :( //the virtio-net interface acts up with ip tunnels :(
setupBridge(t, h) setupBridge(t)
if t.status.RouteError != nil { if t.status.RouteError != nil {
return return
} }
@ -193,7 +190,7 @@ func setupRoute(t *tunnel, h *host.Host) {
} }
func setupBridge(t *tunnel, h *host.Host) { func setupBridge(t *tunnel) {
command := exec.Command("ifconfig", "bridge100") command := exec.Command("ifconfig", "bridge100")
glog.Infof("About to run command: %s\n", command.Args) glog.Infof("About to run command: %s\n", command.Args)
response, err := command.CombinedOutput() response, err := command.CombinedOutput()

View File

@ -24,7 +24,7 @@ import (
"github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/client-go/kubernetes/typed/core/v1" typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
) )
@ -53,7 +53,7 @@ func NewManager() *Manager {
} }
// StartTunnel starts the tunnel // StartTunnel starts the tunnel
func (mgr *Manager) StartTunnel(ctx context.Context, machineName string, machineAPI libmachine.API, configLoader config.Loader, v1Core v1.CoreV1Interface) (done chan bool, err error) { func (mgr *Manager) StartTunnel(ctx context.Context, machineName string, machineAPI libmachine.API, configLoader config.Loader, v1Core typed_core.CoreV1Interface) (done chan bool, err error) {
tunnel, err := newTunnel(machineName, machineAPI, configLoader, v1Core, mgr.registry, mgr.router) tunnel, err := newTunnel(machineName, machineAPI, configLoader, v1Core, mgr.registry, mgr.router)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating tunnel: %s", err) return nil, fmt.Errorf("error creating tunnel: %s", err)

View File

@ -63,6 +63,8 @@ func (t *Status) String() string {
type Route struct { type Route struct {
Gateway net.IP Gateway net.IP
DestCIDR *net.IPNet DestCIDR *net.IPNet
ClusterDomain string
ClusterDNSIP net.IP
} }
func (r *Route) String() string { func (r *Route) String() string {

View File

@ -24,13 +24,13 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/r2d4/external-storage/lib/controller" "github.com/r2d4/external-storage/lib/controller"
"k8s.io/api/core/v1" core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest"
) )
const provisionerName = "k8s.io/minikube-hostpath" const provisionerName = "k8s.io/minikube-hostpath"
@ -55,7 +55,7 @@ func NewHostPathProvisioner() controller.Provisioner {
var _ controller.Provisioner = &hostPathProvisioner{} var _ controller.Provisioner = &hostPathProvisioner{}
// Provision creates a storage asset and returns a PV object representing it. // Provision creates a storage asset and returns a PV object representing it.
func (p *hostPathProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) { func (p *hostPathProvisioner) Provision(options controller.VolumeOptions) (*core.PersistentVolume, error) {
glog.Infof("Provisioning volume %v", options) glog.Infof("Provisioning volume %v", options)
path := path.Join(p.pvDir, options.PVName) path := path.Join(p.pvDir, options.PVName)
if err := os.MkdirAll(path, 0777); err != nil { if err := os.MkdirAll(path, 0777); err != nil {
@ -67,21 +67,21 @@ func (p *hostPathProvisioner) Provision(options controller.VolumeOptions) (*v1.P
return nil, err return nil, err
} }
pv := &v1.PersistentVolume{ pv := &core.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: meta.ObjectMeta{
Name: options.PVName, Name: options.PVName,
Annotations: map[string]string{ Annotations: map[string]string{
"hostPathProvisionerIdentity": string(p.identity), "hostPathProvisionerIdentity": string(p.identity),
}, },
}, },
Spec: v1.PersistentVolumeSpec{ Spec: core.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy, PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy,
AccessModes: options.PVC.Spec.AccessModes, AccessModes: options.PVC.Spec.AccessModes,
Capacity: v1.ResourceList{ Capacity: core.ResourceList{
v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)], core.ResourceStorage: options.PVC.Spec.Resources.Requests[core.ResourceStorage],
}, },
PersistentVolumeSource: v1.PersistentVolumeSource{ PersistentVolumeSource: core.PersistentVolumeSource{
HostPath: &v1.HostPathVolumeSource{ HostPath: &core.HostPathVolumeSource{
Path: path, Path: path,
}, },
}, },
@ -93,7 +93,7 @@ func (p *hostPathProvisioner) Provision(options controller.VolumeOptions) (*v1.P
// Delete removes the storage asset that was created by Provision represented // Delete removes the storage asset that was created by Provision represented
// by the given PV. // by the given PV.
func (p *hostPathProvisioner) Delete(volume *v1.PersistentVolume) error { func (p *hostPathProvisioner) Delete(volume *core.PersistentVolume) error {
glog.Infof("Deleting volume %v", volume) glog.Infof("Deleting volume %v", volume)
ann, ok := volume.Annotations["hostPathProvisionerIdentity"] ann, ok := volume.Annotations["hostPathProvisionerIdentity"]
if !ok { if !ok {
@ -114,7 +114,7 @@ func (p *hostPathProvisioner) Delete(volume *v1.PersistentVolume) error {
// StartStorageProvisioner will start storage provisioner server // StartStorageProvisioner will start storage provisioner server
func StartStorageProvisioner() error { func StartStorageProvisioner() error {
glog.Infof("Initializing the Minikube storage provisioner...") glog.Infof("Initializing the Minikube storage provisioner...")
config, err := restclient.InClusterConfig() config, err := rest.InClusterConfig()
if err != nil { if err != nil {
return err return err
} }
@ -127,7 +127,7 @@ func StartStorageProvisioner() error {
// provisioners aren't officially supported until 1.5 // provisioners aren't officially supported until 1.5
serverVersion, err := clientset.Discovery().ServerVersion() serverVersion, err := clientset.Discovery().ServerVersion()
if err != nil { if err != nil {
return fmt.Errorf("Error getting server version: %v", err) return fmt.Errorf("error getting server version: %v", err)
} }
// Create the provisioner: it implements the Provisioner interface expected by // Create the provisioner: it implements the Provisioner interface expected by

View File

@ -39,7 +39,7 @@ func findNestedElement(s string, c interface{}) (reflect.Value, error) {
// FieldByName returns the zero value if the field does not exist. // FieldByName returns the zero value if the field does not exist.
if e == (reflect.Value{}) { if e == (reflect.Value{}) {
return e, fmt.Errorf("Unable to find field by name: %s", field) return e, fmt.Errorf("unable to find field by name: %s", field)
} }
// Start the loop again, on the next level. // Start the loop again, on the next level.
} }
@ -89,7 +89,7 @@ func convertMap(e reflect.Value, v string) error {
return c == '<' || c == '=' || c == '>' return c == '<' || c == '=' || c == '>'
}) })
if len(subvals) != 2 { if len(subvals) != 2 {
return fmt.Errorf("Unparsable %s", v) return fmt.Errorf("unparsable %s", v)
} }
e.SetMapIndex(reflect.ValueOf(subvals[0]), reflect.ValueOf(subvals[1])) e.SetMapIndex(reflect.ValueOf(subvals[0]), reflect.ValueOf(subvals[1]))
} }
@ -107,7 +107,7 @@ func convertKind(e reflect.Value, v string) error {
case reflect.Bool: case reflect.Bool:
return convertBool(e, v) return convertBool(e, v)
default: default:
return fmt.Errorf("Unable to set type %T", e.Kind()) return fmt.Errorf("unable to set type %T", e.Kind())
} }
} }

View File

@ -176,8 +176,8 @@ func TestSetElement(t *testing.T) {
{"E.J", "otherstring", func(t testConfig) bool { return t.E.J == "otherstring" }}, {"E.J", "otherstring", func(t testConfig) bool { return t.E.J == "otherstring" }},
{"E.K", "17", func(t testConfig) bool { return t.E.K == 17 }}, {"E.K", "17", func(t testConfig) bool { return t.E.K == 17 }},
{"E.L", "1.234", func(t testConfig) bool { return checkFloats(float64(t.E.L), 1.234) }}, {"E.L", "1.234", func(t testConfig) bool { return checkFloats(float64(t.E.L), 1.234) }},
{"D.I.P", "true", func(t testConfig) bool { return bool(t.D.I.P) == true }}, {"D.I.P", "true", func(t testConfig) bool { return t.D.I.P == true }},
{"D.I.P", "false", func(t testConfig) bool { return bool(t.D.I.P) == false }}, {"D.I.P", "false", func(t testConfig) bool { return t.D.I.P == false }},
{"D.I.Q", "11.22.33.44", func(t testConfig) bool { return t.D.I.Q.Equal(net.ParseIP("11.22.33.44")) }}, {"D.I.Q", "11.22.33.44", func(t testConfig) bool { return t.D.I.Q.Equal(net.ParseIP("11.22.33.44")) }},
{"D.I.R", "7-11", func(t testConfig) bool { return t.D.I.R.Base == 7 && t.D.I.R.Size == 5 }}, {"D.I.R", "7-11", func(t testConfig) bool { return t.D.I.R.Base == 7 && t.D.I.R.Size == 5 }},
{"D.I.S", "a,b", func(t testConfig) bool { return reflect.DeepEqual(t.D.I.S, []string{"a", "b"}) }}, {"D.I.S", "a,b", func(t testConfig) bool { return reflect.DeepEqual(t.D.I.S, []string{"a", "b"}) }},

View File

@ -55,7 +55,9 @@ func TestCacheMinikubeISOFromURL(t *testing.T) {
isoPath := filepath.Join(constants.GetMinipath(), "cache", "iso", "minikube-test.iso") isoPath := filepath.Join(constants.GetMinipath(), "cache", "iso", "minikube-test.iso")
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, testISOString) if _, err := io.WriteString(w, testISOString); err != nil {
t.Fatalf("WriteString: %v", err)
}
})) }))
isoURL := server.URL + "/minikube-test.iso" isoURL := server.URL + "/minikube-test.iso"
if err := dler.CacheMinikubeISOFromURL(isoURL); err != nil { if err := dler.CacheMinikubeISOFromURL(isoURL); err != nil {
@ -103,7 +105,9 @@ func TestIsMinikubeISOCached(t *testing.T) {
t.Fatalf("Expected IsMinikubeISOCached with input %s to return %t but instead got: %t", testFileURI, expected, out) t.Fatalf("Expected IsMinikubeISOCached with input %s to return %t but instead got: %t", testFileURI, expected, out)
} }
ioutil.WriteFile(filepath.Join(constants.GetMinipath(), "cache", "iso", "minikube-test.iso"), []byte(testISOString), os.FileMode(int(0644))) if err := ioutil.WriteFile(filepath.Join(constants.GetMinipath(), "cache", "iso", "minikube-test.iso"), []byte(testISOString), os.FileMode(int(0644))); err != nil {
t.Fatalf("WriteFile: %v", err)
}
expected = true expected = true
if out := dler.IsMinikubeISOCached(testFileURI); out != expected { if out := dler.IsMinikubeISOCached(testFileURI); out != expected {

View File

@ -40,14 +40,14 @@ func (es *ExtraOptionSlice) Set(value string) error {
// The component is the value before the first dot. // The component is the value before the first dot.
componentSplit := strings.SplitN(value, ".", 2) componentSplit := strings.SplitN(value, ".", 2)
if len(componentSplit) < 2 { if len(componentSplit) < 2 {
return fmt.Errorf("Invalid value for ExtraOption flag. Value must contain at least one period: %s", value) return fmt.Errorf("invalid value: must contain at least one period: %q", value)
} }
remainder := strings.Join(componentSplit[1:], "") remainder := strings.Join(componentSplit[1:], "")
keySplit := strings.SplitN(remainder, "=", 2) keySplit := strings.SplitN(remainder, "=", 2)
if len(keySplit) != 2 { if len(keySplit) != 2 {
return fmt.Errorf("Invalid value for ExtraOption flag. Value must contain one equal sign: %s", value) return fmt.Errorf("invalid value: must contain one equal sign: %q", value)
} }
e := ExtraOption{ e := ExtraOption{

View File

@ -146,7 +146,9 @@ func TestSetupKubeConfig(t *testing.T) {
} }
test.cfg.SetKubeConfigFile(filepath.Join(tmpDir, "kubeconfig")) test.cfg.SetKubeConfigFile(filepath.Join(tmpDir, "kubeconfig"))
if len(test.existingCfg) != 0 { if len(test.existingCfg) != 0 {
ioutil.WriteFile(test.cfg.GetKubeConfigFile(), test.existingCfg, 0600) if err := ioutil.WriteFile(test.cfg.GetKubeConfigFile(), test.existingCfg, 0600); err != nil {
t.Fatalf("WriteFile: %v", err)
}
} }
err = SetupKubeConfig(test.cfg) err = SetupKubeConfig(test.cfg)
if err != nil && !test.err { if err != nil && !test.err {

View File

@ -22,10 +22,10 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/pkg/errors" "github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1" apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors" apierr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -53,11 +53,11 @@ type PodStore struct {
} }
// List lists the pods // List lists the pods
func (s *PodStore) List() []*v1.Pod { func (s *PodStore) List() []*core.Pod {
objects := s.Store.List() objects := s.Store.List()
pods := make([]*v1.Pod, 0) pods := make([]*core.Pod, 0)
for _, o := range objects { for _, o := range objects {
pods = append(pods, o.(*v1.Pod)) pods = append(pods, o.(*core.Pod))
} }
return pods return pods
} }
@ -84,29 +84,29 @@ func GetClient() (kubernetes.Interface, error) {
} }
// NewPodStore creates a new PodStore // NewPodStore creates a new PodStore
func NewPodStore(c kubernetes.Interface, namespace string, label labels.Selector, field fields.Selector) *PodStore { func NewPodStore(c kubernetes.Interface, namespace string, label fmt.Stringer, field fmt.Stringer) *PodStore {
lw := &cache.ListWatch{ lw := &cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { ListFunc: func(options meta.ListOptions) (runtime.Object, error) {
options.LabelSelector = label.String() options.LabelSelector = label.String()
options.FieldSelector = field.String() options.FieldSelector = field.String()
obj, err := c.Core().Pods(namespace).List(options) obj, err := c.CoreV1().Pods(namespace).List(options)
return runtime.Object(obj), err return runtime.Object(obj), err
}, },
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { WatchFunc: func(options meta.ListOptions) (watch.Interface, error) {
options.LabelSelector = label.String() options.LabelSelector = label.String()
options.FieldSelector = field.String() options.FieldSelector = field.String()
return c.Core().Pods(namespace).Watch(options) return c.CoreV1().Pods(namespace).Watch(options)
}, },
} }
store := cache.NewStore(cache.MetaNamespaceKeyFunc) store := cache.NewStore(cache.MetaNamespaceKeyFunc)
stopCh := make(chan struct{}) stopCh := make(chan struct{})
reflector := cache.NewReflector(lw, &v1.Pod{}, store, 0) reflector := cache.NewReflector(lw, &core.Pod{}, store, 0)
go reflector.Run(stopCh) go reflector.Run(stopCh)
return &PodStore{Store: store, stopCh: stopCh, Reflector: reflector} return &PodStore{Store: store, stopCh: stopCh, Reflector: reflector}
} }
// StartPods starts all pods // StartPods starts all pods
func StartPods(c kubernetes.Interface, namespace string, pod v1.Pod, waitForRunning bool) error { func StartPods(c kubernetes.Interface, namespace string, pod core.Pod, waitForRunning bool) error {
pod.ObjectMeta.Labels["name"] = pod.Name pod.ObjectMeta.Labels["name"] = pod.Name
if waitForRunning { if waitForRunning {
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": pod.Name})) label := labels.SelectorFromSet(labels.Set(map[string]string{"name": pod.Name}))
@ -123,7 +123,7 @@ func WaitForPodsWithLabelRunning(c kubernetes.Interface, ns string, label labels
glog.Infof("Waiting for pod with label %q in ns %q ...", ns, label) glog.Infof("Waiting for pod with label %q in ns %q ...", ns, label)
lastKnownPodNumber := -1 lastKnownPodNumber := -1
return wait.PollImmediate(constants.APICallRetryInterval, ReasonableStartTime, func() (bool, error) { return wait.PollImmediate(constants.APICallRetryInterval, ReasonableStartTime, func() (bool, error) {
listOpts := metav1.ListOptions{LabelSelector: label.String()} listOpts := meta.ListOptions{LabelSelector: label.String()}
pods, err := c.CoreV1().Pods(ns).List(listOpts) pods, err := c.CoreV1().Pods(ns).List(listOpts)
if err != nil { if err != nil {
glog.Infof("error getting Pods with label selector %q [%v]\n", label.String(), err) glog.Infof("error getting Pods with label selector %q [%v]\n", label.String(), err)
@ -140,7 +140,7 @@ func WaitForPodsWithLabelRunning(c kubernetes.Interface, ns string, label labels
} }
for _, pod := range pods.Items { for _, pod := range pods.Items {
if pod.Status.Phase != v1.PodRunning { if pod.Status.Phase != core.PodRunning {
return false, nil return false, nil
} }
} }
@ -150,9 +150,9 @@ func WaitForPodsWithLabelRunning(c kubernetes.Interface, ns string, label labels
} }
// WaitForPodDelete waits for a pod to be deleted // WaitForPodDelete waits for a pod to be deleted
func WaitForPodDelete(c kubernetes.Interface, ns string, label labels.Selector) error { func WaitForPodDelete(c kubernetes.Interface, ns string, label fmt.Stringer) error {
return wait.PollImmediate(constants.APICallRetryInterval, ReasonableMutateTime, func() (bool, error) { return wait.PollImmediate(constants.APICallRetryInterval, ReasonableMutateTime, func() (bool, error) {
listOpts := metav1.ListOptions{LabelSelector: label.String()} listOpts := meta.ListOptions{LabelSelector: label.String()}
pods, err := c.CoreV1().Pods(ns).List(listOpts) pods, err := c.CoreV1().Pods(ns).List(listOpts)
if err != nil { if err != nil {
glog.Infof("error getting Pods with label selector %q [%v]\n", label.String(), err) glog.Infof("error getting Pods with label selector %q [%v]\n", label.String(), err)
@ -165,7 +165,7 @@ func WaitForPodDelete(c kubernetes.Interface, ns string, label labels.Selector)
// WaitForEvent waits for the given event to appear // WaitForEvent waits for the given event to appear
func WaitForEvent(c kubernetes.Interface, ns string, reason string) error { func WaitForEvent(c kubernetes.Interface, ns string, reason string) error {
return wait.PollImmediate(constants.APICallRetryInterval, ReasonableMutateTime, func() (bool, error) { return wait.PollImmediate(constants.APICallRetryInterval, ReasonableMutateTime, func() (bool, error) {
events, err := c.Events().Events("default").List(metav1.ListOptions{}) events, err := c.EventsV1beta1().Events("default").List(meta.ListOptions{})
if err != nil { if err != nil {
glog.Infof("error getting events: %v", err) glog.Infof("error getting events: %v", err)
return false, nil return false, nil
@ -181,21 +181,21 @@ func WaitForEvent(c kubernetes.Interface, ns string, reason string) error {
// WaitForRCToStabilize waits till the RC has a matching generation/replica count between spec and status. // WaitForRCToStabilize waits till the RC has a matching generation/replica count between spec and status.
func WaitForRCToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error { func WaitForRCToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error {
options := metav1.ListOptions{FieldSelector: fields.Set{ options := meta.ListOptions{FieldSelector: fields.Set{
"metadata.name": name, "metadata.name": name,
"metadata.namespace": ns, "metadata.namespace": ns,
}.AsSelector().String()} }.AsSelector().String()}
w, err := c.Core().ReplicationControllers(ns).Watch(options) w, err := c.CoreV1().ReplicationControllers(ns).Watch(options)
if err != nil { if err != nil {
return err return err
} }
_, err = watch.Until(timeout, w, func(event watch.Event) (bool, error) { _, err = watch.Until(timeout, w, func(event watch.Event) (bool, error) {
switch event.Type { if event.Type == watch.Deleted {
case watch.Deleted: return false, apierr.NewNotFound(schema.GroupResource{Resource: "replicationcontrollers"}, "")
return false, apierrs.NewNotFound(schema.GroupResource{Resource: "replicationcontrollers"}, "")
} }
switch rc := event.Object.(type) {
case *v1.ReplicationController: rc, ok := event.Object.(*core.ReplicationController)
if ok {
if rc.Name == name && rc.Namespace == ns && if rc.Name == name && rc.Namespace == ns &&
rc.Generation <= rc.Status.ObservedGeneration && rc.Generation <= rc.Status.ObservedGeneration &&
*(rc.Spec.Replicas) == rc.Status.Replicas { *(rc.Spec.Replicas) == rc.Status.Replicas {
@ -211,7 +211,7 @@ func WaitForRCToStabilize(c kubernetes.Interface, ns, name string, timeout time.
// WaitForDeploymentToStabilize waits till the Deployment has a matching generation/replica count between spec and status. // WaitForDeploymentToStabilize waits till the Deployment has a matching generation/replica count between spec and status.
func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error { func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeout time.Duration) error {
options := metav1.ListOptions{FieldSelector: fields.Set{ options := meta.ListOptions{FieldSelector: fields.Set{
"metadata.name": name, "metadata.name": name,
"metadata.namespace": ns, "metadata.namespace": ns,
}.AsSelector().String()} }.AsSelector().String()}
@ -220,12 +220,11 @@ func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeo
return err return err
} }
_, err = watch.Until(timeout, w, func(event watch.Event) (bool, error) { _, err = watch.Until(timeout, w, func(event watch.Event) (bool, error) {
switch event.Type { if event.Type == watch.Deleted {
case watch.Deleted: return false, apierr.NewNotFound(schema.GroupResource{Resource: "deployments"}, "")
return false, apierrs.NewNotFound(schema.GroupResource{Resource: "deployments"}, "")
} }
switch dp := event.Object.(type) { dp, ok := event.Object.(*apps.Deployment)
case *appsv1.Deployment: if ok {
if dp.Name == name && dp.Namespace == ns && if dp.Name == name && dp.Namespace == ns &&
dp.Generation <= dp.Status.ObservedGeneration && dp.Generation <= dp.Status.ObservedGeneration &&
*(dp.Spec.Replicas) == dp.Status.Replicas { *(dp.Spec.Replicas) == dp.Status.Replicas {
@ -242,12 +241,12 @@ func WaitForDeploymentToStabilize(c kubernetes.Interface, ns, name string, timeo
// WaitForService waits until the service appears (exist == true), or disappears (exist == false) // WaitForService waits until the service appears (exist == true), or disappears (exist == false)
func WaitForService(c kubernetes.Interface, namespace, name string, exist bool, interval, timeout time.Duration) error { func WaitForService(c kubernetes.Interface, namespace, name string, exist bool, interval, timeout time.Duration) error {
err := wait.PollImmediate(interval, timeout, func() (bool, error) { err := wait.PollImmediate(interval, timeout, func() (bool, error) {
_, err := c.Core().Services(namespace).Get(name, metav1.GetOptions{}) _, err := c.CoreV1().Services(namespace).Get(name, meta.GetOptions{})
switch { switch {
case err == nil: case err == nil:
glog.Infof("Service %s in namespace %s found.", name, namespace) glog.Infof("Service %s in namespace %s found.", name, namespace)
return exist, nil return exist, nil
case apierrs.IsNotFound(err): case apierr.IsNotFound(err):
glog.Infof("Service %s in namespace %s disappeared.", name, namespace) glog.Infof("Service %s in namespace %s disappeared.", name, namespace)
return !exist, nil return !exist, nil
case !IsRetryableAPIError(err): case !IsRetryableAPIError(err):
@ -269,7 +268,7 @@ func WaitForService(c kubernetes.Interface, namespace, name string, exist bool,
func WaitForServiceEndpointsNum(c kubernetes.Interface, namespace, serviceName string, expectNum int, interval, timeout time.Duration) error { func WaitForServiceEndpointsNum(c kubernetes.Interface, namespace, serviceName string, expectNum int, interval, timeout time.Duration) error {
return wait.Poll(interval, timeout, func() (bool, error) { return wait.Poll(interval, timeout, func() (bool, error) {
glog.Infof("Waiting for amount of service:%s endpoints to be %d", serviceName, expectNum) glog.Infof("Waiting for amount of service:%s endpoints to be %d", serviceName, expectNum)
list, err := c.Core().Endpoints(namespace).List(metav1.ListOptions{}) list, err := c.CoreV1().Endpoints(namespace).List(meta.ListOptions{})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -283,7 +282,7 @@ func WaitForServiceEndpointsNum(c kubernetes.Interface, namespace, serviceName s
}) })
} }
func countEndpointsNum(e *v1.Endpoints) int { func countEndpointsNum(e *core.Endpoints) int {
num := 0 num := 0
for _, sub := range e.Subsets { for _, sub := range e.Subsets {
num += len(sub.Addresses) num += len(sub.Addresses)
@ -293,5 +292,5 @@ func countEndpointsNum(e *v1.Endpoints) int {
// IsRetryableAPIError returns if this error is retryable or not // IsRetryableAPIError returns if this error is retryable or not
func IsRetryableAPIError(err error) bool { func IsRetryableAPIError(err error) bool {
return apierrs.IsTimeout(err) || apierrs.IsServerTimeout(err) || apierrs.IsTooManyRequests(err) || apierrs.IsInternalError(err) return apierr.IsTimeout(err) || apierr.IsServerTimeout(err) || apierr.IsTooManyRequests(err) || apierr.IsInternalError(err)
} }

View File

@ -98,11 +98,15 @@ var testSHAString = "test"
func TestParseSHAFromURL(t *testing.T) { func TestParseSHAFromURL(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, testSHAString) 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) { serverBadResponse := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 HTTP status code returned!")) if _, err := w.Write([]byte("500 HTTP status code returned!")); err != nil {
t.Fatalf("Write: %v", err)
}
})) }))
argsList := [...]getTestArgs{ argsList := [...]getTestArgs{
@ -175,7 +179,9 @@ func TestTeePrefix(t *testing.T) {
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
TeePrefix(":", &in, &out, logSink) if err := TeePrefix(":", &in, &out, logSink); err != nil {
t.Errorf("TeePrefix: %v", err)
}
wg.Done() wg.Done()
}() }()

80
test.sh
View File

@ -14,56 +14,42 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
set -e set -eu -o pipefail
# Check for python on host, and use it if possible, otherwise fall back on python dockerized exitcode=0
if [[ -f $(which python 2>&1) ]]; then
PYTHON="python" echo "= go mod ================================================================"
go mod download >/dev/null || ((exitcode+=1))
go mod tidy -v && echo ok || ((exitcode+=2))
echo "= make lint ============================================================="
make -s lint && 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 || true)"
if [[ -n "${missing}" ]]; then
echo "boilerplate missing: $missing"
echo "consider running: ${BDIR}/fix.sh"
((exitcode+=4))
else else
PYTHON="docker run --rm -it -v $(pwd):/minikube -w /minikube python python" echo "ok"
fi fi
echo "= schema_check =========================================================="
go run deploy/minikube/schema_check.go >/dev/null && echo ok || ((exitcode+=8))
COV_FILE=coverage.txt echo "= go test ==============================================================="
COV_TMP_FILE=coverage_tmp.txt cov_tmp="$(mktemp)"
readonly COVERAGE_PATH=./out/coverage.txt
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}"
# Run "go test" on packages that have test files. Also create coverage profile exit "${exitcode}"
echo "Running go tests..."
rm -f out/$COV_FILE || true
echo "mode: count" > out/$COV_FILE
for pkg in $(go list -f '{{ if .TestGoFiles }} {{.ImportPath}} {{end}}' ./cmd/... ./pkg/...); do
go test -tags "container_image_ostree_stub containers_image_openpgp" -v $pkg -covermode=count -coverprofile=out/$COV_TMP_FILE
# tail -n +2 skips the first line of the file
# for coverprofile the first line is the `mode: count` line which we only want once in our file
tail -n +2 out/$COV_TMP_FILE >> out/$COV_FILE || (echo "Unable to append coverage for $pkg" && exit 1)
done
rm out/$COV_TMP_FILE
# Ignore these paths in the following tests.
ignore="vendor\|\_gopath\|assets.go\|out\/"
# Check gofmt
echo "Checking gofmt..."
set +e
files=$(gofmt -l -s . | grep -v ${ignore})
set -e
if [[ $files ]]; then
gofmt -d ${files}
echo "Gofmt errors in files: $files"
exit 1
fi
# Check boilerplate
echo "Checking boilerplate..."
BOILERPLATEDIR=./hack/boilerplate
# Grep returns a non-zero exit code if we don't match anything, which is good in this case.
set +e
files=$(${PYTHON} ${BOILERPLATEDIR}/boilerplate.py --rootdir . --boilerplate-dir ${BOILERPLATEDIR} | grep -v $ignore)
set -e
if [[ ! -z ${files} ]]; then
echo "Boilerplate missing in: ${files}."
exit 1
fi
echo "Checking releases.json schema"
go run deploy/minikube/schema_check.go

View File

@ -39,7 +39,11 @@ func testClusterDNS(t *testing.T) {
kr := util.NewKubectlRunner(t) kr := util.NewKubectlRunner(t)
busybox := busyBoxPod(t, client, kr) busybox := busyBoxPod(t, client, kr)
defer kr.RunCommand([]string{"delete", "po", busybox}) defer func() {
if _, err := kr.RunCommand([]string{"delete", "po", busybox}); err != nil {
t.Errorf("delete failed: %v", err)
}
}()
out := []byte{} out := []byte{}

View File

@ -36,8 +36,9 @@ func TestDocker(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel() defer cancel()
// Pre-cleanup: this usually fails, because no instance is running. if _, _, err := mk.RunWithContext(ctx, "delete"); err != nil {
mk.RunWithContext(ctx, "delete") t.Logf("pre-delete failed (probably ok): %v", err)
}
startCmd := fmt.Sprintf("start %s %s %s", mk.StartArgs, mk.Args, 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") "--docker-env=FOO=BAR --docker-env=BAZ=BAT --docker-opt=debug --docker-opt=icc=true --alsologtostderr --v=5")

View File

@ -147,7 +147,7 @@ func verifyFiles(minikubeRunner util.MinikubeRunner, kubectlRunner *util.Kubectl
} }
// test that file written from pod can be read from host echo test > /mount-9p/frompod; in pod // test that file written from pod can be read from host echo test > /mount-9p/frompod; in pod
if string(out) != expected { if string(out) != expected {
return fmt.Errorf("Expected file %s to contain text %s, was %s.", path, expected, out) return fmt.Errorf("expected file %s to contain text %q, was %q", path, expected, out)
} }
// test that file written from host was read in by the pod via cat /mount-9p/fromhost; // test that file written from host was read in by the pod via cat /mount-9p/fromhost;
@ -155,7 +155,7 @@ func verifyFiles(minikubeRunner util.MinikubeRunner, kubectlRunner *util.Kubectl
return err return err
} }
if string(out) != expected { if string(out) != expected {
return fmt.Errorf("Expected file %s to contain text %s, was %s.", path, expected, out) return fmt.Errorf("expected file %s to contain text %q, was %q", path, expected, out)
} }
// test file timestamps are correct // test file timestamps are correct

View File

@ -26,7 +26,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
api "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
commonutil "k8s.io/minikube/pkg/util" commonutil "k8s.io/minikube/pkg/util"
@ -60,7 +60,7 @@ func testProvisioning(t *testing.T) {
if len(scl.Items) > 0 { if len(scl.Items) > 0 {
return nil return nil
} }
return fmt.Errorf("No default StorageClass yet.") 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, 5*time.Second, 20); err != nil {
@ -94,7 +94,7 @@ func testProvisioning(t *testing.T) {
// And check that it gets bound to a PV. // And check that it gets bound to a PV.
checkStorage := func() error { checkStorage := func() error {
pvc := api.PersistentVolumeClaim{} pvc := core.PersistentVolumeClaim{}
if err := kubectlRunner.RunCommandParseOutput(pvcCmd, &pvc); err != nil { if err := kubectlRunner.RunCommandParseOutput(pvcCmd, &pvc); err != nil {
return err return err
} }

View File

@ -125,6 +125,7 @@ func testTunnel(t *testing.T) {
} }
} }
// getResponseBody returns the contents of a URL
func getResponseBody(address string) (string, error) { func getResponseBody(address string) (string, error) {
httpClient := http.DefaultClient httpClient := http.DefaultClient
httpClient.Timeout = 5 * time.Second httpClient.Timeout = 5 * time.Second

View File

@ -94,7 +94,9 @@ func (m *MinikubeRunner) teeRun(cmd *exec.Cmd) (string, string, error) {
return "", "", err return "", "", err
} }
cmd.Start() if err := cmd.Start(); err != nil {
return "", "", err
}
var outB bytes.Buffer var outB bytes.Buffer
var errB bytes.Buffer var errB bytes.Buffer
var wg sync.WaitGroup var wg sync.WaitGroup

View File

@ -17,6 +17,7 @@ limitations under the License.
package integration package integration
import ( import (
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -26,6 +27,7 @@ import (
"github.com/docker/machine/libmachine/state" "github.com/docker/machine/libmachine/state"
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/constants"
pkgutil "k8s.io/minikube/pkg/util" pkgutil "k8s.io/minikube/pkg/util"
"k8s.io/minikube/test/integration/util" "k8s.io/minikube/test/integration/util"
) )
@ -63,19 +65,14 @@ func TestVersionUpgrade(t *testing.T) {
} }
} }
releaseRunner := util.MinikubeRunner{ releaseRunner := util.MinikubeRunner{BinaryPath: tf.Name(), T: t}
Args: currentRunner.Args, // For full coverage: also test upgrading from oldest to newest supported k8s release
BinaryPath: tf.Name(), releaseRunner.Start(fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion))
StartArgs: currentRunner.StartArgs,
MountArgs: currentRunner.MountArgs,
T: t,
}
releaseRunner.Start()
releaseRunner.CheckStatus(state.Running.String()) releaseRunner.CheckStatus(state.Running.String())
releaseRunner.RunCommand("stop", true) releaseRunner.RunCommand("stop", true)
releaseRunner.CheckStatus(state.Stopped.String()) releaseRunner.CheckStatus(state.Stopped.String())
currentRunner.Start() currentRunner.Start(fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion))
currentRunner.CheckStatus(state.Running.String()) currentRunner.CheckStatus(state.Running.String())
currentRunner.RunCommand("delete", true) currentRunner.RunCommand("delete", true)
currentRunner.CheckStatus(state.None.String()) currentRunner.CheckStatus(state.None.String())