Skip to content

Commit

Permalink
add CIFS/SMB based file sharing for windows
Browse files Browse the repository at this point in the history
it allows users to mount the host's home folder at
/mnt/c/users/$username directory in the crc vm

to determine if folder sharing is supported/enabled it
checks that a smb share named 'crc-dir0' exists which
should've been created during msi installation

since CIFS/SMB is a network file system and needs a username
and password for getting access two new fields 'SharedDirUsername'
and 'SharedDirPassword' is added to the MachineConfig and StartConfig
structs
  • Loading branch information
anjannath committed Oct 11, 2022
1 parent c502056 commit b4cfc0e
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 23 deletions.
20 changes: 11 additions & 9 deletions pkg/crc/machine/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ type MachineConfig struct {
BundleName string

// Virtual machine configuration
Name string
Memory int
CPUs int
DiskSize int
ImageSourcePath string
ImageFormat string
SSHKeyPath string
KubeConfig string
SharedDirs []string
Name string
Memory int
CPUs int
DiskSize int
ImageSourcePath string
ImageFormat string
SSHKeyPath string
KubeConfig string
SharedDirs []string
SharedDirPassword string
SharedDirUsername string

// macOS specific configuration
KernelCmdLine string
Expand Down
16 changes: 16 additions & 0 deletions pkg/crc/machine/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,19 @@ func setDiskSize(host *host.Host, diskSizeGiB int) error {

return updateDriverValue(host, diskSizeSetter)
}

func setSharedDirPassword(host *host.Host, password string) error {
driver, err := loadDriverConfig(host)
if err != nil {
return err
}

if len(driver.SharedDirs) == 0 {
return nil
}

for i := range driver.SharedDirs {
driver.SharedDirs[i].Password = password
}
return updateDriverStruct(host, driver)
}
5 changes: 5 additions & 0 deletions pkg/crc/machine/driver_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
machineVf "github.com/code-ready/crc/pkg/drivers/vfkit"
"github.com/code-ready/crc/pkg/libmachine"
"github.com/code-ready/crc/pkg/libmachine/host"
"github.com/code-ready/machine/libmachine/drivers"
)

func newHost(api libmachine.API, machineConfig config.MachineConfig) (*host.Host, error) {
Expand Down Expand Up @@ -64,3 +65,7 @@ func updateKernelArgs(vm *virtualMachine) error {
}
return vm.api.Save(vm.Host)
}

func updateDriverStruct(host *host.Host, driver *machineVf.Driver) error {
return drivers.ErrNotImplemented
}
5 changes: 5 additions & 0 deletions pkg/crc/machine/driver_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/code-ready/crc/pkg/libmachine"
"github.com/code-ready/crc/pkg/libmachine/host"
machineLibvirt "github.com/code-ready/machine/drivers/libvirt"
"github.com/code-ready/machine/libmachine/drivers"
)

func newHost(api libmachine.API, machineConfig config.MachineConfig) (*host.Host, error) {
Expand Down Expand Up @@ -47,3 +48,7 @@ func (r *RPCServerDriver) SetConfigRaw(data []byte, _ *struct{}) error {
return json.Unmarshal(data, &r.ActualDriver)
}
*/

func updateDriverStruct(host *host.Host, driver *machineLibvirt.Driver) error {
return drivers.ErrNotImplemented
}
5 changes: 5 additions & 0 deletions pkg/crc/machine/driver_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ func updateDriverConfig(host *host.Host, driver *machineHyperv.Driver) error {
func updateKernelArgs(vm *virtualMachine) error {
return nil
}

func updateDriverStruct(host *host.Host, driver *machineHyperv.Driver) error {
host.Driver = driver
return nil
}
34 changes: 34 additions & 0 deletions pkg/crc/machine/hyperv/driver_windows.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package hyperv

import (
"path/filepath"
"strings"

"github.com/code-ready/crc/pkg/crc/constants"
"github.com/code-ready/crc/pkg/crc/machine/config"
"github.com/code-ready/crc/pkg/crc/network"
"github.com/code-ready/crc/pkg/drivers/hyperv"
winnet "github.com/code-ready/crc/pkg/os/windows/network"
"github.com/code-ready/machine/libmachine/drivers"
)

func CreateHost(machineConfig config.MachineConfig) *hyperv.Driver {
Expand All @@ -23,5 +27,35 @@ func CreateHost(machineConfig config.MachineConfig) *hyperv.Driver {
hypervDriver.VirtualSwitch = switchName
}

hypervDriver.SharedDirs = configureShareDirs(machineConfig)
return hypervDriver
}

// converts a path like c:\users\crc to /mnt/c/users/crc
func convertToUnixPath(path string) string {
/* podman internally converts windows style paths like C:\Users\crc to
* /mnt/c/Users/crc so it expects the shared folder to be mounted under
* '/mnt' instead of '/' like in the case of macOS and linux
* see: https://github.com/containers/podman/blob/468aa6478c73e4acd8708ce8bb0bb5a056f329c2/pkg/specgen/winpath.go#L24-L59
*/
path = filepath.ToSlash(path)
if len(path) > 1 && path[1] == ':' {
return ("/mnt/" + strings.ToLower(path[0:1]) + path[2:])
}
return path
}

func configureShareDirs(machineConfig config.MachineConfig) []drivers.SharedDir {
var sharedDirs []drivers.SharedDir
for _, dir := range machineConfig.SharedDirs {
sharedDir := drivers.SharedDir{
Source: dir,
Target: convertToUnixPath(dir),
Tag: "crc-dir0", // smb share 'crc-dir0' is created in the msi
Type: "cifs",
Username: machineConfig.SharedDirUsername,
}
sharedDirs = append(sharedDirs, sharedDir)
}
return sharedDirs
}
12 changes: 12 additions & 0 deletions pkg/crc/machine/hyperv/driver_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package hyperv

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestConvertToUnixPath(t *testing.T) {
assert.Equal(t, "/mnt/c/Users/crc", convertToUnixPath("C:\\Users\\crc"))
assert.Equal(t, "/mnt/d/Users/crc", convertToUnixPath("d:\\Users\\crc"))
}
41 changes: 28 additions & 13 deletions pkg/crc/machine/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ func (client *client) updateVMConfig(startConfig types.StartConfig, vm *virtualM
}
}

// we want to set the shared dir password on-the-fly to be used
// we do not want this value to be persisted to disk
if startConfig.SharedDirPassword != "" {
if err := setSharedDirPassword(vm.Host, startConfig.SharedDirPassword); err != nil {
return fmt.Errorf("Failed to set shared dir password: %w", err)
}
}

return nil
}

Expand Down Expand Up @@ -178,6 +186,11 @@ func configureSharedDirs(vm *virtualMachine, sshRunner *crcssh.Runner) error {
if _, _, err := sshRunner.RunPrivileged(fmt.Sprintf("Mounting %s", mount.Target), "mount", "-o", "context=\"system_u:object_r:container_file_t:s0\"", "-t", mount.Type, mount.Tag, mount.Target); err != nil {
return err
}
case "cifs":
smbUncPath := fmt.Sprintf("//%s/%s", hostVirtualIP, mount.Tag)
if _, _, err := sshRunner.RunPrivate("sudo", "mount", "-o", fmt.Sprintf("rw,uid=core,gid=core,username='%s',password='%s'", mount.Username, mount.Password), "-t", mount.Type, smbUncPath, mount.Target); err != nil {
return fmt.Errorf("Failed to mount CIFS/SMB share '%s' please make sure configured password is correct: %w", mount.Tag, err)
}
default:
return fmt.Errorf("Unknown Shared dir type requested: %s", mount.Type)
}
Expand Down Expand Up @@ -233,19 +246,21 @@ func (client *client) Start(ctx context.Context, startConfig types.StartConfig)
}

machineConfig := config.MachineConfig{
Name: client.name,
BundleName: bundleName,
CPUs: startConfig.CPUs,
Memory: startConfig.Memory,
DiskSize: startConfig.DiskSize,
NetworkMode: client.networkMode(),
ImageSourcePath: crcBundleMetadata.GetDiskImagePath(),
ImageFormat: crcBundleMetadata.GetDiskImageFormat(),
SSHKeyPath: crcBundleMetadata.GetSSHKeyPath(),
KernelCmdLine: crcBundleMetadata.GetKernelCommandLine(),
Initramfs: crcBundleMetadata.GetInitramfsPath(),
Kernel: crcBundleMetadata.GetKernelPath(),
SharedDirs: sharedDirs,
Name: client.name,
BundleName: bundleName,
CPUs: startConfig.CPUs,
Memory: startConfig.Memory,
DiskSize: startConfig.DiskSize,
NetworkMode: client.networkMode(),
ImageSourcePath: crcBundleMetadata.GetDiskImagePath(),
ImageFormat: crcBundleMetadata.GetDiskImageFormat(),
SSHKeyPath: crcBundleMetadata.GetSSHKeyPath(),
KernelCmdLine: crcBundleMetadata.GetKernelCommandLine(),
Initramfs: crcBundleMetadata.GetInitramfsPath(),
Kernel: crcBundleMetadata.GetKernelPath(),
SharedDirs: sharedDirs,
SharedDirPassword: startConfig.SharedDirPassword,
SharedDirUsername: startConfig.SharedDirUsername,
}
if crcBundleMetadata.IsOpenShift() {
machineConfig.KubeConfig = crcBundleMetadata.GetKubeConfigPath()
Expand Down
4 changes: 3 additions & 1 deletion pkg/crc/machine/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ type StartConfig struct {
Preset crcpreset.Preset

// Shared dirs
EnableSharedDirs bool
EnableSharedDirs bool
SharedDirPassword string
SharedDirUsername string

// Ports to access openshift routes
IngressHTTPPort uint
Expand Down
1 change: 1 addition & 0 deletions pkg/crc/machine/vsock.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func listOpenPorts(daemonClient *daemonclient.Client) ([]types.ExposeRequest, er

const (
virtualMachineIP = "192.168.127.2"
hostVirtualIP = "192.168.127.254"
internalSSHPort = "22"
localIP = "127.0.0.1"
remoteHTTPPort = "80"
Expand Down
9 changes: 9 additions & 0 deletions pkg/drivers/hyperv/hyperv_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,12 @@ func (d *Driver) GetIP() (string, error) {

return resp[0], nil
}

func (d *Driver) GetSharedDirs() ([]drivers.SharedDir, error) {
for _, dir := range d.SharedDirs {
if !smbShareExists(dir.Tag) {
return []drivers.SharedDir{}, nil
}
}
return d.SharedDirs, nil
}
7 changes: 7 additions & 0 deletions pkg/drivers/hyperv/powershell_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,10 @@ func quote(text string) string {
func toMb(value int) string {
return fmt.Sprintf("%dMB", value)
}

func smbShareExists(name string) bool {
if err := cmd(fmt.Sprintf("Get-SmbShare -Name %s", name)); err != nil {
return false
}
return true
}

0 comments on commit b4cfc0e

Please sign in to comment.