diff --git a/cmd/minikube/cmd/kubectl.go b/cmd/minikube/cmd/kubectl.go new file mode 100644 index 0000000000..f25bffdb00 --- /dev/null +++ b/cmd/minikube/cmd/kubectl.go @@ -0,0 +1,88 @@ +/* +Copyright 2019 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "fmt" + "os" + "os/exec" + "runtime" + "syscall" + + "github.com/golang/glog" + "github.com/spf13/cobra" + pkg_config "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/console" + "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/machine" +) + +// kubectlCmd represents the kubectl command +var kubectlCmd = &cobra.Command{ + Use: "kubectl", + Short: "Run kubectl", + Long: `Run the kubernetes client, download it if necessary.`, + Run: func(cmd *cobra.Command, args []string) { + api, err := machine.NewAPIClient() + if err != nil { + fmt.Fprintf(os.Stderr, "Error getting client: %v\n", err) + os.Exit(1) + } + defer api.Close() + + cc, err := pkg_config.Load() + if err != nil && !os.IsNotExist(err) { + console.ErrLn("Error loading profile config: %v", err) + } + + binary := "kubectl" + if runtime.GOOS == "windows" { + binary = "kubectl.exe" + } + + version := constants.DefaultKubernetesVersion + if cc != nil { + version = cc.KubernetesConfig.KubernetesVersion + } + + path, err := machine.CacheBinary(binary, version, runtime.GOOS, runtime.GOARCH) + if err != nil { + exit.WithError("Failed to download kubectl", err) + } + + glog.Infof("Running %s %v", path, args) + c := exec.Command(path, args...) + c.Stdout = os.Stdout + c.Stderr = os.Stderr + if err := c.Run(); err != nil { + var rc int + if exitError, ok := err.(*exec.ExitError); ok { + waitStatus := exitError.Sys().(syscall.WaitStatus) + rc = waitStatus.ExitStatus() + } else { + fmt.Fprintf(os.Stderr, "Error running %s: %v\n", path, err) + rc = 1 + } + os.Exit(rc) + } + }, +} + +func init() { + RootCmd.AddCommand(kubectlCmd) +} diff --git a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go index dde133e34c..c40046604f 100644 --- a/pkg/minikube/bootstrapper/kubeadm/kubeadm.go +++ b/pkg/minikube/bootstrapper/kubeadm/kubeadm.go @@ -22,6 +22,7 @@ import ( "fmt" "net" "net/http" + "runtime" "strings" "time" @@ -572,7 +573,7 @@ func downloadBinaries(cfg config.KubernetesConfig, c bootstrapper.CommandRunner) for _, bin := range constants.GetKubeadmCachedBinaries() { bin := bin g.Go(func() error { - path, err := machine.CacheBinary(bin, cfg.KubernetesVersion) + path, err := machine.CacheBinary(bin, cfg.KubernetesVersion, "linux", runtime.GOARCH) if err != nil { return errors.Wrapf(err, "downloading %s", bin) } diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index 2e4d23e3df..c96b06fe46 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -20,7 +20,6 @@ import ( "fmt" "os" "path/filepath" - "runtime" "strings" "time" @@ -221,13 +220,13 @@ const ( ) // GetKubernetesReleaseURL gets the location of a kubernetes client -func GetKubernetesReleaseURL(binaryName, version string) string { - return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/linux/%s/%s", version, runtime.GOARCH, binaryName) +func GetKubernetesReleaseURL(binaryName, version, osName, archName string) string { + return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) } // GetKubernetesReleaseURLSHA1 gets the location of a kubernetes client checksum -func GetKubernetesReleaseURLSHA1(binaryName, version string) string { - return fmt.Sprintf("%s.sha1", GetKubernetesReleaseURL(binaryName, version)) +func GetKubernetesReleaseURLSHA1(binaryName, version, osName, archName string) string { + return fmt.Sprintf("%s.sha1", GetKubernetesReleaseURL(binaryName, version, osName, archName)) } // IsMinikubeChildProcess is the name of "is minikube child process" variable diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index cd1a083d5c..7ffb27c434 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -20,6 +20,7 @@ import ( "crypto" "os" "path" + "runtime" "github.com/golang/glog" "github.com/jimmidyson/go-download" @@ -39,7 +40,7 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er for _, bin := range binaries { bin := bin g.Go(func() error { - if _, err := CacheBinary(bin, version); err != nil { + if _, err := CacheBinary(bin, version, "linux", runtime.GOARCH); err != nil { return errors.Wrapf(err, "caching image %s", bin) } return nil @@ -49,11 +50,11 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er } // CacheBinary will cache a binary on the host -func CacheBinary(binary, version string) (string, error) { +func CacheBinary(binary, version, osName, archName string) (string, error) { targetDir := constants.MakeMiniPath("cache", version) targetFilepath := path.Join(targetDir, binary) - url := constants.GetKubernetesReleaseURL(binary, version) + url := constants.GetKubernetesReleaseURL(binary, version, osName, archName) _, err := os.Stat(targetFilepath) // If it exists, do no verification and continue @@ -73,13 +74,18 @@ func CacheBinary(binary, version string) (string, error) { Mkdirs: download.MkdirAll, } - options.Checksum = constants.GetKubernetesReleaseURLSHA1(binary, version) + options.Checksum = constants.GetKubernetesReleaseURLSHA1(binary, version, osName, archName) options.ChecksumHash = crypto.SHA1 console.OutStyle("file-download", "Downloading %s %s", binary, version) if err := download.ToFile(url, targetFilepath, options); err != nil { return "", errors.Wrapf(err, "Error downloading %s %s", binary, version) } + if osName == runtime.GOOS && archName == runtime.GOARCH { + if err = os.Chmod(targetFilepath, 0755); err != nil { + return "", errors.Wrapf(err, "chmod +x %s", targetFilepath) + } + } return targetFilepath, nil }