diff --git a/cmd/minikube/cmd/delete.go b/cmd/minikube/cmd/delete.go index f3c645518a..38095c97c6 100644 --- a/cmd/minikube/cmd/delete.go +++ b/cmd/minikube/cmd/delete.go @@ -21,6 +21,7 @@ import ( "os" "github.com/spf13/cobra" + cmdUtil "k8s.io/minikube/cmd/util" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/machine" ) @@ -45,6 +46,10 @@ associated files.`, os.Exit(1) } fmt.Println("Machine deleted.") + + if err := cmdUtil.KillMountProcess(); err != nil { + fmt.Println("Errors occurred deleting mount process: ", err) + } }, } diff --git a/cmd/minikube/cmd/mount.go b/cmd/minikube/cmd/mount.go index 056d3d50bd..1578a7e120 100644 --- a/cmd/minikube/cmd/mount.go +++ b/cmd/minikube/cmd/mount.go @@ -26,14 +26,15 @@ import ( "github.com/golang/glog" "github.com/spf13/cobra" + cmdUtil "k8s.io/minikube/cmd/util" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/machine" "k8s.io/minikube/third_party/go9p/ufs" ) var mountIP string +var isKill bool // mountCmd represents the mount command var mountCmd = &cobra.Command{ @@ -41,6 +42,14 @@ var mountCmd = &cobra.Command{ Short: "Mounts the specified directory into minikube", Long: `Mounts the specified directory into minikube.`, Run: func(cmd *cobra.Command, args []string) { + if isKill { + if err := cmdUtil.KillMountProcess(); err != nil { + fmt.Println("Errors occurred deleting mount process: ", err) + os.Exit(1) + } + os.Exit(0) + } + if len(args) != 1 { errText := `Please specify the directory to be mounted: \tminikube mount HOST_MOUNT_DIRECTORY:VM_MOUNT_DIRECTORY(ex:"/host-home:/vm-home") @@ -104,13 +113,18 @@ var mountCmd = &cobra.Command{ } fmt.Printf("Mounting %s into %s on the minikubeVM\n", hostPath, vmPath) fmt.Println("This daemon process needs to stay alive for the mount to still be accessible...") + port, err := cmdUtil.GetPort() + if err != nil { + glog.Errorln("Error finding port for mount: ", err) + os.Exit(1) + } var wg sync.WaitGroup wg.Add(1) go func() { - ufs.StartServer(net.JoinHostPort(ip.String(), constants.DefaultUfsPort), debugVal, hostPath) + ufs.StartServer(net.JoinHostPort(ip.String(), port), debugVal, hostPath) wg.Done() }() - err = cluster.MountHost(api, vmPath, ip) + err = cluster.MountHost(api, vmPath, ip, port) if err != nil { fmt.Println(err.Error()) os.Exit(1) @@ -121,5 +135,6 @@ var mountCmd = &cobra.Command{ func init() { mountCmd.Flags().StringVar(&mountIP, "ip", "", "Specify the ip that the mount should be setup on") + mountCmd.Flags().BoolVar(&isKill, "kill", false, "Kill the mount process spawned by minikube start") RootCmd.AddCommand(mountCmd) } diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 7f2238efce..69c909938f 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -19,6 +19,7 @@ package cmd import ( "fmt" "os" + "os/exec" "path/filepath" "strconv" "strings" @@ -30,6 +31,8 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "io/ioutil" + cmdUtil "k8s.io/minikube/cmd/util" "k8s.io/minikube/pkg/minikube/cluster" cfg "k8s.io/minikube/pkg/minikube/config" @@ -55,9 +58,11 @@ const ( hypervVirtualSwitch = "hyperv-virtual-switch" kvmNetwork = "kvm-network" keepContext = "keep-context" + noMount = "no-mount" featureGates = "feature-gates" apiServerName = "apiserver-name" dnsDomain = "dns-domain" + mountString = "mount-string" ) var ( @@ -197,8 +202,35 @@ func runStart(cmd *cobra.Command, args []string) { cmdUtil.MaybeReportErrorAndExit(err) } + fmt.Printf("Setting up hostmount on %s...\n", viper.GetString(mountString)) + // start 9p server mount + if !viper.GetBool(noMount) || cfg.GetMachineName() != constants.DefaultMachineName { + path := os.Args[0] + mountDebugVal := 0 + if glog.V(8) { + mountDebugVal = 1 + } + mountCmd := exec.Command(path, "mount", fmt.Sprintf("--v=%d", mountDebugVal), viper.GetString(mountString)) + mountCmd.Env = append(os.Environ(), constants.IsMinikubeChildProcess+"=true") + if glog.V(8) { + mountCmd.Stdout = os.Stdout + mountCmd.Stderr = os.Stderr + } + err = mountCmd.Start() + if err != nil { + glog.Errorf("Error running command minikube mount %s", err) + cmdUtil.MaybeReportErrorAndExit(err) + } + err = ioutil.WriteFile(filepath.Join(constants.GetMinipath(), constants.MountProcessFileName), []byte(strconv.Itoa(mountCmd.Process.Pid)), 0644) + if err != nil { + glog.Errorf("Error writing mount process pid to file: %s", err) + cmdUtil.MaybeReportErrorAndExit(err) + } + } + if kubeCfgSetup.KeepContext { - fmt.Printf("The local Kubernetes cluster has started. The kubectl context has not been altered, kubectl will require \"--context=%s\" to use the local Kubernetes cluster.\n", kubeCfgSetup.ClusterName) + fmt.Printf("The local Kubernetes cluster has started. The kubectl context has not been altered, kubectl will require \"--context=%s\" to use the local Kubernetes cluster.\n", + kubeCfgSetup.ClusterName) } else { fmt.Println("Kubectl is now configured to use the cluster.") } @@ -227,6 +259,8 @@ func calculateDiskSizeInMB(humanReadableDiskSize string) int { func init() { startCmd.Flags().Bool(keepContext, constants.DefaultKeepContext, "This will keep the existing kubectl context and will create a minikube context.") + startCmd.Flags().Bool(noMount, constants.DefaultNoMount, "This will not start the mount daemon and automatically mount files into minikube") + startCmd.Flags().String(mountString, constants.DefaultMountDir+":"+constants.DefaultMountEndpoint, "The argument to pass the minikube mount command on start") startCmd.Flags().String(isoURL, constants.DefaultIsoUrl, "Location of the minikube iso") startCmd.Flags().String(vmDriver, constants.DefaultVMDriver, fmt.Sprintf("VM driver is one of: %v", constants.SupportedVMDrivers)) startCmd.Flags().Int(memory, constants.DefaultMemory, "Amount of RAM allocated to the minikube VM") diff --git a/cmd/minikube/cmd/stop.go b/cmd/minikube/cmd/stop.go index 4da51e913d..3461dae442 100644 --- a/cmd/minikube/cmd/stop.go +++ b/cmd/minikube/cmd/stop.go @@ -46,6 +46,10 @@ itself, leaving all files intact. The cluster can be started again with the "sta cmdUtil.MaybeReportErrorAndExit(err) } fmt.Println("Machine stopped.") + + if err := cmdUtil.KillMountProcess(); err != nil { + fmt.Println("Errors occurred deleting mount process: ", err) + } }, } diff --git a/cmd/minikube/main.go b/cmd/minikube/main.go index 93f8f4f839..352c5783cc 100644 --- a/cmd/minikube/main.go +++ b/cmd/minikube/main.go @@ -17,12 +17,12 @@ limitations under the License. package main import ( - "github.com/pkg/profile" - "k8s.io/minikube/cmd/minikube/cmd" - "k8s.io/minikube/pkg/minikube/machine" - "os" + "github.com/pkg/profile" + "k8s.io/minikube/cmd/minikube/cmd" + "k8s.io/minikube/pkg/minikube/constants" + "k8s.io/minikube/pkg/minikube/machine" _ "k8s.io/minikube/pkg/provision" ) @@ -32,6 +32,8 @@ func main() { if os.Getenv(minikubeEnvPrefix) == "1" { defer profile.Start(profile.TraceProfile).Stop() } - machine.StartDriver() + if os.Getenv(constants.IsMinikubeChildProcess) == "" { + machine.StartDriver() + } cmd.Execute() } diff --git a/cmd/util/util.go b/cmd/util/util.go index 88112a4a2f..1fd76a521b 100644 --- a/cmd/util/util.go +++ b/cmd/util/util.go @@ -22,13 +22,18 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" + "net" "net/http" "os" "os/exec" + "path/filepath" "runtime" "strings" "time" + "strconv" + "github.com/golang/glog" "github.com/pkg/errors" "github.com/spf13/viper" @@ -210,3 +215,34 @@ minikube config set WantKubectlDownloadMsg false verb, fmt.Sprintf(installInstructions, constants.DefaultKubernetesVersion, goos, runtime.GOARCH)) } } + +// Ask the kernel for a free open port that is ready to use +func GetPort() (string, error) { + addr, err := net.ResolveTCPAddr("tcp", "localhost:0") + if err != nil { + panic(err) + } + + l, err := net.ListenTCP("tcp", addr) + if err != nil { + return "", errors.Errorf("Error accessing port %d", addr.Port) + } + defer l.Close() + return strconv.Itoa(l.Addr().(*net.TCPAddr).Port), nil +} + +func KillMountProcess() error { + out, err := ioutil.ReadFile(filepath.Join(constants.GetMinipath(), constants.MountProcessFileName)) + if err != nil { + return errors.Wrap(err, "error reading mount process from file") + } + pid, err := strconv.Atoi(string(out)) + if err != nil { + return errors.Wrap(err, "error converting mount string to pid") + } + mountProc, err := os.FindProcess(pid) + if err != nil { + return errors.Wrap(err, "error converting mount string to pid") + } + return mountProc.Kill() +} diff --git a/hack/jenkins/common.sh b/hack/jenkins/common.sh index 0800df52f1..9cfff28482 100644 --- a/hack/jenkins/common.sh +++ b/hack/jenkins/common.sh @@ -46,7 +46,7 @@ sudo rm -rf $HOME/.minikube || true # Allow this to fail, we'll switch on the return code below. set +e -out/e2e-${OS_ARCH} -minikube-args="--vm-driver=${VM_DRIVER} --v=10" -test.v -test.timeout=30m -binary=out/minikube-${OS_ARCH} +out/e2e-${OS_ARCH} -minikube-args="--vm-driver=${VM_DRIVER} --v=10 --no-mount" -test.v -test.timeout=30m -binary=out/minikube-${OS_ARCH} result=$? set -e diff --git a/hack/jenkins/windows_integration_test_hyperv.ps1 b/hack/jenkins/windows_integration_test_hyperv.ps1 index 1031ee0b52..be563bda12 100644 --- a/hack/jenkins/windows_integration_test_hyperv.ps1 +++ b/hack/jenkins/windows_integration_test_hyperv.ps1 @@ -21,7 +21,7 @@ gsutil.cmd cp -r gs://minikube-builds/$env:MINIKUBE_LOCATION/testdata . ./out/minikube-windows-amd64.exe delete Remove-Item -Recurse -Force C:\Users\jenkins\.minikube -out/e2e-windows-amd64.exe --% -minikube-args="--vm-driver=hyperv --hyperv-virtual-switch=Minikube --cpus=4 $env:EXTRA_BUILD_ARGS" -test.v -test.timeout=30m -binary=out/minikube-windows-amd64.exe +out/e2e-windows-amd64.exe --% -minikube-args="--vm-driver=hyperv --hyperv-virtual-switch=Minikube --cpus=4 $env:EXTRA_BUILD_ARGS --no-mount" -test.v -test.timeout=30m -binary=out/minikube-windows-amd64.exe $env:result=$lastexitcode # If the last exit code was 0->success, x>0->error diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index d5c6914703..584d83cfa9 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -402,7 +402,7 @@ func GetHostLogs(api libmachine.API, follow bool) (string, error) { } // MountHost runs the mount command from the 9p client on the VM to the 9p server on the host -func MountHost(api libmachine.API, path string, ip net.IP) error { +func MountHost(api libmachine.API, path string, ip net.IP, port string) error { host, err := CheckIfApiExistsAndLoad(api) if err != nil { return errors.Wrap(err, "Error checking that api exists and loading it") @@ -414,7 +414,7 @@ func MountHost(api libmachine.API, path string, ip net.IP) error { } } host.RunSSHCommand(GetMountCleanupCommand(path)) - mountCmd, err := GetMountCommand(ip, path) + mountCmd, err := GetMountCommand(ip, path, port) if err != nil { return errors.Wrap(err, "Error getting mount command") } diff --git a/pkg/minikube/cluster/commands.go b/pkg/minikube/cluster/commands.go index 69769b7348..3ea73cc234 100644 --- a/pkg/minikube/cluster/commands.go +++ b/pkg/minikube/cluster/commands.go @@ -184,18 +184,20 @@ sudo rm -rf %s; var mountTemplate = ` sudo mkdir -p {{.Path}}; -sudo mount -t 9p -o trans=tcp -o port=5640 -o uid=1001 -o gid=1001 {{.IP}} {{.Path}}; +sudo mount -t 9p -o trans=tcp -o port={{.Port}} -o uid=1001 -o gid=1001 {{.IP}} {{.Path}}; sudo chmod 775 {{.Path}};` -func GetMountCommand(ip net.IP, path string) (string, error) { +func GetMountCommand(ip net.IP, path string, port string) (string, error) { t := template.Must(template.New("mountCommand").Parse(mountTemplate)) buf := bytes.Buffer{} data := struct { IP string Path string + Port string }{ IP: ip.String(), Path: path, + Port: port, } if err := t.Execute(&buf, data); err != nil { return "", err diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index d9761a9f64..e1992debe9 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -73,6 +73,8 @@ func MakeMiniPath(fileName ...string) string { return filepath.Join(args...) } +var MountProcessFileName = ".mount-process" + // Only pass along these flags to localkube. var LogFlags = [...]string{ "v", @@ -127,4 +129,7 @@ const ( const ( DefaultUfsPort = "5640" DefaultUfsDebugLvl = 0 + DefaultNoMount = false ) + +const IsMinikubeChildProcess = "IS_MINIKUBE_CHILD_PROCESS" diff --git a/pkg/minikube/constants/constants_darwin.go b/pkg/minikube/constants/constants_darwin.go index bedf1a8797..b2926de44c 100644 --- a/pkg/minikube/constants/constants_darwin.go +++ b/pkg/minikube/constants/constants_darwin.go @@ -23,3 +23,6 @@ var SupportedVMDrivers = [...]string{ "xhyve", "vmwarefusion", } + +var DefaultMountDir = "/Users" +var DefaultMountEndpoint = "/Users" diff --git a/pkg/minikube/constants/constants_linux.go b/pkg/minikube/constants/constants_linux.go index baa9b0ff09..a2e8abff36 100644 --- a/pkg/minikube/constants/constants_linux.go +++ b/pkg/minikube/constants/constants_linux.go @@ -18,7 +18,14 @@ limitations under the License. package constants +import ( + "k8s.io/client-go/util/homedir" +) + var SupportedVMDrivers = [...]string{ "virtualbox", "kvm", } + +var DefaultMountDir = homedir.HomeDir() +var DefaultMountEndpoint = "/hosthome" diff --git a/pkg/minikube/constants/constants_windows.go b/pkg/minikube/constants/constants_windows.go index 693ccfc5a3..ccd158f86a 100644 --- a/pkg/minikube/constants/constants_windows.go +++ b/pkg/minikube/constants/constants_windows.go @@ -18,7 +18,14 @@ limitations under the License. package constants +import ( + "k8s.io/client-go/util/homedir" +) + var SupportedVMDrivers = [...]string{ "virtualbox", "hyperv", } + +var DefaultMountDir = homedir.HomeDir() +var DefaultMountEndpoint = "/hostmount"