Vagrant with Hyper-V issues on SMB synced folders

I've recently been working with Hyper-V under Vagrant, as my company is transitioning off of MacBooks with the recent decision by Apple to drop Intel support completely. We've primarily been a Mac shop for as long as I've been around, but we use both Linux and Windows guest VMs underneath Vagrant, and Apple Silicon/ARM just isn't viable for us with that. On the other hand, WSL2 and VirtualBox with Windows guest VMs don't play nicely. (Surprisingly, Linux guest VMs show zero issues, but the problems for Windows guests are severe and debilitating. 2012r2 was vaguely usable, but 2019 is virtually impossible, and we've been trying to update things across the board, with SQL 2019 specifically driving the migration off of 2012r2, something I'm happy to see taking place)

Trying to consolidate on the Vagrant Hyper-V provider when running on a Windows host, I'm now running into an issue with Linux guest VMs (for which we are using the bento/ubuntu-18.04 box). Since Hyper-V does not have direct synced folder support like VirtualBox does, we need to use SMB synced folders instead. We do not support SMB v1 on the Windows hosts, which has caused a bit of problem getting synced folders working. The magic combination that I found on this front was to do something like so:

linux.vm.synced_folder '.', '/vagrant',
  mount_options: ['vers=3.0', "domain=#{WINDOWS_DOMAIN}", "username=#{WINDOWS_USERNAME}"], 
  smb_username: "#{WINDOWS_DOMAIN}\\#{WINDOWS_USERNAME}"

(For some reason, using just smb_username in DOMAIN\username format does not work with mount.cifs, and username@domain.tld does not work on the PowerShell side of the equation. I tried both against my local computer and the domain that it is joined to, both connected to the corporate network [across the VPN] and disconnected, but it always fails unless it's in the DOMAIN\username format. And I'm not sure if SMB v2 will work, but v3 definitely does.)

In any case, that worked perfectly fine in a non-Chef based Linux Vagrant VM, and it also works for a Chef VM that has additional synced folders. (test-kitchen setups using Linux with kitchen-vagrant and Hyper-V also work fine, but it does not appear to use synced folders in that configuration.) What fails is the synced folders set up through what appears to be vagrant-berkshelf (although I may be incorrect and it may just be through the Vagrant chef-solo provider); those seem to inherit the smb_username setting from the base Vagrant folder, but they don't inherit the mount_options, as I can see the mount.cifs command that fails both shows it using vers=2.0 and it does not have the additional domain and username segments:

==> linux: Mounting SMB shared folders...
    linux: C:/git/mycompany/chef-productA => /vagrant
    linux: C:/git/mycompany/moto => /opt/localstack/moto
    linux: C:/git/mycompany/localstack => /opt/localstack/localstack
    linux: C:/git/mycompany/shared-services-admin => /opt/shared/shared-services-admin
    linux: C:/Users/USERNAME/.berkshelf/vagrant-berkshelf/shelves/berkshelf20220613-31204-z5isoa-linux => /tmp/vagrant-chef/fec6333d5db94e713120b0f1ac71d06f/cookbooks
Failed to mount folders in Linux guest. This is usually because
the "vboxsf" file system is not available. Please verify that
the guest additions are properly installed in the guest and
can work properly. The command attempted was:

mount -t cifs -o vers=2.0,credentials=/etc/smb_creds_vgt-fd62d096bfbd28ce5877b987bd60009c-3ab543756cd5034504e158cc51eabcce,uid=1000,gid=1000,mfsymlinks,_netdev,nofail //172.22.240.1/vgt-fd62d096bfbd28ce5877b987bd60009c-3ab543756cd5034504e158cc51eabcce /tmp/vagrant-chef/fec6333d5db94e713120b0f1ac71d06f/cookbooks

The error output from the last command was:

mount error(13): Permission denied
Refer to the mount.cifs(8) manual page (e.g. man mount.cifs)
PS C:\git\mycompany\chef-producta> vagrant ssh linux
...
vagrant@dev-productA-linux:~$ grep cifs /etc/mtab
//172.22.240.1/vgt-fd62d096bfbd28ce5877b987bd60009c-6ad5fdbcbf2eaa93bd62f92333a2e6e5 /vagrant cifs rw,relatime,vers=3.0,cache=strict,username=USERNAME,domain=DOMAIN,uid=1000,forceuid,gid=1000,forcegid,addr=172.22.240.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,mfsymlinks,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1 0 0
//172.22.240.1/vgt-fd62d096bfbd28ce5877b987bd60009c-8e956c6569108cb0e8c67f291c860d5e /opt/localstack/moto cifs rw,relatime,vers=3.0,cache=strict,username=USERNAME,domain=DOMAIN,uid=1000,forceuid,gid=1000,forcegid,addr=172.22.240.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,mfsymlinks,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1 0 0
//172.22.240.1/vgt-fd62d096bfbd28ce5877b987bd60009c-ed98907b1e19e2a08f51cdf7f582bebe /opt/localstack/localstack cifs rw,relatime,vers=3.0,cache=strict,username=USERNAME,domain=DOMAIN,uid=1000,forceuid,gid=1000,forcegid,addr=172.22.240.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,mfsymlinks,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1 0 0
//172.22.240.1/vgt-fd62d096bfbd28ce5877b987bd60009c-c7f4eedd0ee55d38dd7809632eab0768 /opt/shared/shared-services-admin cifs rw,relatime,vers=3.0,cache=strict,username=USERNAME,domain=DOMAIN,uid=1000,forceuid,gid=1000,forcegid,addr=172.22.240.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,mfsymlinks,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1 0 0
vagrant@dev-productA-linux:~$

I'm not seeing anything about how to configure this on the pages for vagrant-berkshelf or the chef-solo provider for Vagrant. Any tips on this front would be greatly appreciated, as I really don't want to try enabling SMB v1 to work around this problem, particularly with our new parent company's security team.

After looking at the Vagrant code, I see this is user error on my part. I'm traditionally used to seeing Windows usernames in the format of either MYDOMAIN\myusername or myusername@mydomain.tld. However, the Vagrant template in plugins/guests/linux/cap/mount_smb_shared_folder.rb indicates that it splits apart the smb_username value on the @ sign into the domain and username portions when it writes out the credentials file that mount.cifs ends up using, like so:

          # If a domain is provided in the username, separate it
          username, domain = (options[:smb_username] || '').split('@', 2)
...
          # Write the credentials file
          machine.communicate.sudo(<<-SCRIPT)
cat <<"EOF" >/etc/smb_creds_#{name}
username=#{username}
password=#{smb_password}
#{domain ? "domain=#{domain}" : ""}
EOF
chmod 0600 /etc/smb_creds_#{name}
SCRIPT

Setting smb_username to username@DOMAIN then was successful, both in Vagrant creating the shares on the Windows host and mounting it on the Linux guest VM.

Hopefully this helps someone else the next time they're Googling the issue :slight_smile: