Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add all mount flags to start command #12930

Merged
merged 12 commits into from
Dec 10, 2021
44 changes: 32 additions & 12 deletions cmd/minikube/cmd/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/klog/v2"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/detect"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
Expand All @@ -43,11 +44,30 @@ import (

const (
// nineP is the value of --type used for the 9p filesystem.
nineP = "9p"
defaultMountVersion = "9p2000.L"
defaultMsize = 262144
nineP = "9p"
defaultMount9PVersion = "9p2000.L"
mount9PVersionDescription = "Specify the 9p version that the mount should use"
defaultMountGID = "docker"
mountGIDDescription = "Default group id used for the mount"
defaultMountIP = ""
mountIPDescription = "Specify the ip that the mount should be setup on"
defaultMountMode = 0o755
mountModeDescription = "File permissions used for the mount"
defaultMountMSize = 262144
mountMSizeDescription = "The number of bytes to use for 9p packet payload"
mountOptionsDescription = "Additional mount options, such as cache=fscache"
defaultMountPort = 0
mountPortDescription = "Specify the port that the mount should be setup on, where 0 means any free port."
defaultMountType = nineP
mountTypeDescription = "Specify the mount filesystem type (supported types: 9p)"
defaultMountUID = "docker"
mountUIDDescription = "Default user id used for the mount"
)

func defaultMountOptions() []string {
return []string{}
}

// placeholders for flag values
var (
mountIP string
Expand Down Expand Up @@ -218,16 +238,16 @@ var mountCmd = &cobra.Command{
}

func init() {
mountCmd.Flags().StringVar(&mountIP, "ip", "", "Specify the ip that the mount should be setup on")
mountCmd.Flags().Uint16Var(&mountPort, "port", 0, "Specify the port that the mount should be setup on, where 0 means any free port.")
mountCmd.Flags().StringVar(&mountType, "type", nineP, "Specify the mount filesystem type (supported types: 9p)")
mountCmd.Flags().StringVar(&mountVersion, "9p-version", defaultMountVersion, "Specify the 9p version that the mount should use")
mountCmd.Flags().StringVar(&mountIP, constants.MountIPFlag, defaultMountIP, mountIPDescription)
mountCmd.Flags().Uint16Var(&mountPort, constants.MountPortFlag, defaultMountPort, mountPortDescription)
mountCmd.Flags().StringVar(&mountType, constants.MountTypeFlag, defaultMountType, mountTypeDescription)
mountCmd.Flags().StringVar(&mountVersion, constants.Mount9PVersionFlag, defaultMount9PVersion, mount9PVersionDescription)
mountCmd.Flags().BoolVar(&isKill, "kill", false, "Kill the mount process spawned by minikube start")
mountCmd.Flags().StringVar(&uid, "uid", "docker", "Default user id used for the mount")
mountCmd.Flags().StringVar(&gid, "gid", "docker", "Default group id used for the mount")
mountCmd.Flags().UintVar(&mode, "mode", 0o755, "File permissions used for the mount")
mountCmd.Flags().StringSliceVar(&options, "options", []string{}, "Additional mount options, such as cache=fscache")
mountCmd.Flags().IntVar(&mSize, "msize", defaultMsize, "The number of bytes to use for 9p packet payload")
mountCmd.Flags().StringVar(&uid, constants.MountUIDFlag, defaultMountUID, mountUIDDescription)
mountCmd.Flags().StringVar(&gid, constants.MountGIDFlag, defaultMountGID, mountGIDDescription)
mountCmd.Flags().UintVar(&mode, constants.MountModeFlag, defaultMountMode, mountModeDescription)
mountCmd.Flags().StringSliceVar(&options, constants.MountOptionsFlag, defaultMountOptions(), mountOptionsDescription)
mountCmd.Flags().IntVar(&mSize, constants.MountMSizeFlag, defaultMountMSize, mountMSizeDescription)
}

// getPort uses the requested port or asks the kernel for a free open port that is ready to use
Expand Down
50 changes: 50 additions & 0 deletions cmd/minikube/cmd/start_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ const (
imageRepository = "image-repository"
imageMirrorCountry = "image-mirror-country"
mountString = "mount-string"
mount9PVersion = "mount-9p-version"
mountGID = "mount-gid"
mountIPFlag = "mount-ip"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some have "Flag" at the end and some do not. Are all of these flags? Could we drop "Flag" for consistency between these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mountIP, mountPort & mountType are already defined in mount.go so I had to differentiate them

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, works for me.

mountMode = "mount-mode"
mountMSize = "mount-msize"
mountOptions = "mount-options"
mountPortFlag = "mount-port"
mountTypeFlag = "mount-type"
mountUID = "mount-uid"
disableDriverMounts = "disable-driver-mounts"
cacheImages = "cache-images"
uuid = "uuid"
Expand Down Expand Up @@ -153,6 +162,15 @@ func initMinikubeFlags() {
startCmd.Flags().String(containerRuntime, constants.DefaultContainerRuntime, fmt.Sprintf("The container runtime to be used (%s).", strings.Join(cruntime.ValidRuntimes(), ", ")))
startCmd.Flags().Bool(createMount, false, "This will start the mount daemon and automatically mount files into minikube.")
startCmd.Flags().String(mountString, constants.DefaultMountDir+":/minikube-host", "The argument to pass the minikube mount command on start.")
startCmd.Flags().String(mount9PVersion, defaultMount9PVersion, mount9PVersionDescription)
startCmd.Flags().String(mountGID, defaultMountGID, mountGIDDescription)
startCmd.Flags().String(mountIPFlag, defaultMountIP, mountIPDescription)
startCmd.Flags().Uint(mountMode, defaultMountMode, mountModeDescription)
startCmd.Flags().Int(mountMSize, defaultMountMSize, mountMSizeDescription)
startCmd.Flags().StringSlice(mountOptions, defaultMountOptions(), mountOptionsDescription)
startCmd.Flags().Uint16(mountPortFlag, defaultMountPort, mountPortDescription)
startCmd.Flags().String(mountTypeFlag, defaultMountType, mountTypeDescription)
startCmd.Flags().String(mountUID, defaultMountUID, mountUIDDescription)
startCmd.Flags().StringSlice(config.AddonListFlag, nil, "Enable addons. see `minikube addons list` for a list of valid addon names.")
startCmd.Flags().String(criSocket, "", "The cri socket path to be used.")
startCmd.Flags().String(networkPlugin, "", "Kubelet network plug-in to use (default: auto)")
Expand Down Expand Up @@ -466,6 +484,15 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, drvName s
CertExpiration: viper.GetDuration(certExpiration),
Mount: viper.GetBool(createMount),
MountString: viper.GetString(mountString),
Mount9PVersion: viper.GetString(mount9PVersion),
MountGID: viper.GetString(mountGID),
MountIP: viper.GetString(mountIPFlag),
MountMode: viper.GetUint(mountMode),
MountMSize: viper.GetInt(mountMSize),
MountOptions: viper.GetStringSlice(mountOptions),
MountPort: uint16(viper.GetUint(mountPortFlag)),
MountType: viper.GetString(mountTypeFlag),
MountUID: viper.GetString(mountUID),
KubernetesConfig: config.KubernetesConfig{
KubernetesVersion: k8sVersion,
ClusterName: ClusterFlagValue(),
Expand Down Expand Up @@ -675,6 +702,15 @@ func updateExistingConfigFromFlags(cmd *cobra.Command, existing *config.ClusterC
updateDurationFromFlag(cmd, &cc.CertExpiration, certExpiration)
updateBoolFromFlag(cmd, &cc.Mount, createMount)
updateStringFromFlag(cmd, &cc.MountString, mountString)
updateStringFromFlag(cmd, &cc.Mount9PVersion, mount9PVersion)
updateStringFromFlag(cmd, &cc.MountGID, mountGID)
updateStringFromFlag(cmd, &cc.MountIP, mountIPFlag)
updateUintFromFlag(cmd, &cc.MountMode, mountMode)
updateIntFromFlag(cmd, &cc.MountMSize, mountMSize)
updateStringSliceFromFlag(cmd, &cc.MountOptions, mountOptions)
updateUint16FromFlag(cmd, &cc.MountPort, mountPortFlag)
updateStringFromFlag(cmd, &cc.MountType, mountTypeFlag)
updateStringFromFlag(cmd, &cc.MountUID, mountUID)

if cmd.Flags().Changed(kubernetesVersion) {
cc.KubernetesConfig.KubernetesVersion = getKubernetesVersion(existing)
Expand Down Expand Up @@ -746,6 +782,20 @@ func updateDurationFromFlag(cmd *cobra.Command, v *time.Duration, key string) {
}
}

// updateUintFromFlag will update the existing uint from the flag.
func updateUintFromFlag(cmd *cobra.Command, v *uint, key string) {
if cmd.Flags().Changed(key) {
*v = viper.GetUint(key)
}
}

// updateUint16FromFlag will update the existing uint16 from the flag.
func updateUint16FromFlag(cmd *cobra.Command, v *uint16, key string) {
if cmd.Flags().Changed(key) {
*v = uint16(viper.GetUint(key))
}
}

// interpretWaitFlag interprets the wait flag and respects the legacy minikube users
// returns map of components to wait for
func interpretWaitFlag(cmd cobra.Command) map[string]bool {
Expand Down
9 changes: 9 additions & 0 deletions pkg/minikube/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ type ClusterConfig struct {
CertExpiration time.Duration
Mount bool
MountString string
Mount9PVersion string
MountGID string
MountIP string
MountMode uint
MountMSize int
MountOptions []string
MountPort uint16
MountType string
MountUID string
}

// KubernetesConfig contains the parameters used to configure the VM Kubernetes.
Expand Down
19 changes: 19 additions & 0 deletions pkg/minikube/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,25 @@ const (

// DefaultCertExpiration is the amount of time in the future a certificate will expire in by default, which is 3 years
DefaultCertExpiration = time.Hour * 24 * 365 * 3

// Mount9PVersionFlag is the flag used to set the mount 9P version
Mount9PVersionFlag = "9p-version"
// MountGIDFlag is the flag used to set the mount GID
MountGIDFlag = "gid"
// MountIPFlag is the flag used to set the mount IP
MountIPFlag = "ip"
// MountMSizeFlag is the flag used to set the mount msize
MountMSizeFlag = "msize"
// MountModeFlag is the flag used to set the mount mode
MountModeFlag = "mode"
// MountOptionsFlag is the flag used to set the mount options
MountOptionsFlag = "options"
// MountPortFlag is the flag used to set the mount port
MountPortFlag = "port"
// MountTypeFlag is the flag used to set the mount type
MountTypeFlag = "type"
// MountUIDFlag is the flag used to set the mount UID
MountUIDFlag = "uid"
)

var (
Expand Down
45 changes: 37 additions & 8 deletions pkg/minikube/node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,20 @@ func showVersionInfo(k8sVersion string, cr cruntime.Manager) {
}

// configureMounts configures any requested filesystem mounts
func configureMounts(wg *sync.WaitGroup, mount bool, mountString string) {
func configureMounts(wg *sync.WaitGroup, cc config.ClusterConfig) {
wg.Add(1)
defer wg.Done()

if !mount {
if !cc.Mount {
return
}

out.Step(style.Mounting, "Creating mount {{.name}} ...", out.V{"name": mountString})
out.Step(style.Mounting, "Creating mount {{.name}} ...", out.V{"name": cc.MountString})
path := os.Args[0]
mountDebugVal := 0
if klog.V(8).Enabled() {
mountDebugVal = 1
}
profile := viper.GetString("profile")
mountCmd := exec.Command(path, "mount", "-p", profile, fmt.Sprintf("--v=%d", mountDebugVal), mountString)

args := generateMountArgs(profile, cc)
mountCmd := exec.Command(path, args...)
mountCmd.Env = append(os.Environ(), constants.IsMinikubeChildProcess+"=true")
if klog.V(8).Enabled() {
mountCmd.Stdout = os.Stdout
Expand All @@ -79,3 +77,34 @@ func configureMounts(wg *sync.WaitGroup, mount bool, mountString string) {
exit.Error(reason.HostMountPid, "Error writing mount pid", err)
}
}

func generateMountArgs(profile string, cc config.ClusterConfig) []string {
mountDebugVal := 0
if klog.V(8).Enabled() {
mountDebugVal = 1
}

args := []string{"mount", cc.MountString}
flags := []struct {
name string
value string
}{
{"profile", profile},
{"v", fmt.Sprintf("%d", mountDebugVal)},
{constants.Mount9PVersionFlag, cc.Mount9PVersion},
{constants.MountGIDFlag, cc.MountGID},
{constants.MountIPFlag, cc.MountIP},
{constants.MountMSizeFlag, fmt.Sprintf("%d", cc.MountMSize)},
{constants.MountModeFlag, fmt.Sprintf("%d", cc.MountMode)},
{constants.MountPortFlag, fmt.Sprintf("%d", cc.MountPort)},
{constants.MountTypeFlag, cc.MountType},
{constants.MountUIDFlag, cc.MountUID},
}
for _, flag := range flags {
sharifelgamal marked this conversation as resolved.
Show resolved Hide resolved
args = append(args, fmt.Sprintf("--%s", flag.name), flag.value)
}
for _, option := range cc.MountOptions {
args = append(args, fmt.Sprintf("--%s", constants.MountOptionsFlag), option)
}
return args
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any cases where flags could possess inconsistent values?

Should we have logic, to say, for example, that mountSize value is out of range (maybe we want to do this in a separate PR).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I can add that is a follow up PR, I created an issue

#13142

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense!

}
2 changes: 1 addition & 1 deletion pkg/minikube/node/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func Start(starter Starter, apiServer bool) (*kubeconfig.Settings, error) {

var wg sync.WaitGroup
if !driver.IsKIC(starter.Cfg.Driver) {
go configureMounts(&wg, starter.Cfg.Mount, starter.Cfg.MountString)
go configureMounts(&wg, *starter.Cfg)
}

wg.Add(1)
Expand Down
63 changes: 61 additions & 2 deletions test/integration/mount_start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,20 @@ package integration

import (
"context"
"fmt"
"os/exec"
"strings"
"testing"
)

const (
mountGID = "0"
mountMSize = "6543"
mountMode = "0777"
mountPort = "46464"
mountUID = "0"
)

// TestMountStart tests using the mount command on start
func TestMountStart(t *testing.T) {
if NoneDriver() {
Expand Down Expand Up @@ -72,7 +82,7 @@ func TestMountStart(t *testing.T) {
func validateStartWithMount(ctx context.Context, t *testing.T, profile string) {
defer PostMortemLogs(t, profile)

args := []string{"start", "-p", profile, "--memory=2048", "--mount"}
args := []string{"start", "-p", profile, "--memory=2048", "--mount", "--mount-gid", mountGID, "--mount-msize", mountMSize, "--mount-mode", mountMode, "--mount-port", mountPort, "--mount-uid", mountUID}
args = append(args, StartArgs()...)
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
Expand All @@ -84,11 +94,60 @@ func validateStartWithMount(ctx context.Context, t *testing.T, profile string) {
func validateMount(ctx context.Context, t *testing.T, profile string) {
defer PostMortemLogs(t, profile)

args := []string{"-p", profile, "ssh", "ls", "/minikube-host"}
sshArgs := []string{"-p", profile, "ssh", "--"}

args := sshArgs
args = append(args, "ls", "/minikube-host")
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("mount failed: %q : %v", rr.Command(), err)
}

// Docker has it's own mounting method, it doesn't respect the mounting flags
if DockerDriver() {
return
}

args = sshArgs
args = append(args, "stat", "--format", "'%a'", "/minikube-host")
rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("failed to get directory mode: %v", err)
}

want := "777"
spowelljr marked this conversation as resolved.
Show resolved Hide resolved
if !strings.Contains(rr.Output(), want) {
t.Errorf("wanted mode to be %q; got: %q", want, rr.Output())
}

// We can't get the mount details with Hyper-V
if HyperVDriver() {
return
}

args = sshArgs
args = append(args, "mount", "|", "grep", "9p")
rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("failed to get mount information: %v", err)
}

flags := []struct {
key string
expected string
}{
{"gid", mountGID},
{"msize", mountMSize},
{"port", mountPort},
{"uid", mountUID},
}

for _, flag := range flags {
want := fmt.Sprintf("%s=%s", flag.key, flag.expected)
if !strings.Contains(rr.Output(), want) {
t.Errorf("wanted gid to be: %q; got: %q", want, rr.Output())
}
}
}

// validateMountStop stops a cluster
Expand Down