Add smb_start capability for darwin

This commit is contained in:
Chris Roberts 2017-12-21 15:57:57 -08:00
parent 68439f6bac
commit 98ec1af30e
9 changed files with 129 additions and 9 deletions

View File

@ -4,4 +4,6 @@ Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -E -e /*/ d -ibak /etc/exports
Cmnd_Alias VAGRANT_SMB_ADD = /usr/sbin/sharing -a * -S * -s * -g * -n *
Cmnd_Alias VAGRANT_SMB_REMOVE = /usr/sbin/sharing -r *
Cmnd_Alias VAGRANT_SMB_LIST = /usr/sbin/sharing -l
%admin ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE, VAGRANT_SMB_ADD, VAGRANT_SMB_REMOVE, VAGRANT_SMB_LIST
Cmnd_Alias VAGRANT_SMB_PSTART = /bin/launchctl load -w /System/Library/LaunchDaemons/com.apple.smb.preferences.plist
Cmnd_Alias VAGRANT_SMB_DSTART = /bin/launchctl load -w /System/Library/LaunchDaemons/com.apple.smb.preferences.plist
%admin ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE, VAGRANT_SMB_ADD, VAGRANT_SMB_REMOVE, VAGRANT_SMB_LIST, VAGRANT_SMB_PSTART, VAGRANT_SMB_DSTART

View File

@ -10,6 +10,40 @@ module VagrantPlugins
File.exist?("/usr/sbin/sharing")
end
# Check if the required SMB services are loaded and enabled. If they are
# not, then start them up
def self.smb_start(env)
result = Vagrant::Util::Subprocess.execute("pwpolicy", "gethashtypes")
if result.exit_code == 0 && !result.stdout.include?("SMB-NT")
@@logger.error("SMB compatible password has not been stored")
raise SyncedFolderSMB::Errors::SMBCredentialsMissing
end
result = Vagrant::Util::Subprocess.execute("launchctl", "list", "com.apple.smb.preferences")
if result.exit_code != 0
@@logger.warn("smb preferences service not enabled. enabling and starting...")
cmd = ["/bin/launchctl", "load", "-w", "/System/Library/LaunchDaemons/com.apple.smb.preferences.plist"]
result = Vagrant::Util::Subprocess.execute("/usr/bin/sudo", *cmd)
if result.exit_code != 0
raise SyncedFolderSMB::Errors::SMBStartFailed,
command: cmd.join(" "),
stderr: result.stderr,
stdout: result.stdout
end
end
result = Vagrant::Util::Subprocess.execute("launchctl", "list", "com.apple.smbd")
if result.exit_code != 0
@@logger.warn("smbd service not enabled. enabling and starting...")
cmd = ["/bin/launchctl", "load", "-w", "/System/Library/LaunchDaemons/com.apple.smbd.plist"]
result = Vagrant::Util::Subprocess.execute("/usr/bin/sudo", *cmd)
if result.exit_code != 0
raise SyncedFolderSMB::Errors::SMBStartFailed,
command: cmd.join(" "),
stderr: result.stderr,
stdout: result.stdout
end
end
end
# Required options for mounting a share hosted
# on macos.
def self.smb_mount_options(env)

View File

@ -41,6 +41,11 @@ module VagrantPlugins
Cap::SMB
end
host_capability("darwin", "smb_start") do
require_relative "cap/smb"
Cap::SMB
end
host_capability("darwin", "configured_ip_addresses") do
require_relative "cap/configured_ip_addresses"
Cap::ConfiguredIPAddresses

View File

@ -10,6 +10,14 @@ module VagrantPlugins
error_key(:not_supported)
end
class SMBStartFailed < SMBError
error_key(:start_failed)
end
class SMBCredentialsMissing < SMBError
error_key(:credentials_missing)
end
class DefineShareFailed < SMBError
error_key(:define_share_failed)
end

View File

@ -30,6 +30,11 @@ module VagrantPlugins
def prepare(machine, folders, opts)
machine.ui.output(I18n.t("vagrant_sf_smb.preparing"))
# Check if this host can start and SMB service
if machine.env.host.capability?(:smb_start)
machine.env.host.capability(:smb_start)
end
smb_username = smb_password = nil
# If we need auth information, then ask the user.

View File

@ -1,9 +1,10 @@
en:
vagrant_sf_smb:
not_supported: |-
It appears your machine doesn't support SMB, or there is not an
adapter to enable SMB on this machine for Vagrant. Ensure SMB
host functionality is available on this machine and try again.
It appears your machine doesn't support SMB, has not been
properly configured for SMB, or there is not an adapter to
enable SMB on this machine for Vagrant. Ensure SMB host
functionality is available on this machine and try again.
mounting: |-
Mounting SMB shared folders...
mounting_single: |-
@ -23,6 +24,19 @@ en:
Vagrant requires administator access to create SMB shares and
may request access to complete setup of configured shares.
errors:
start_failed: |-
Vagrant failed to automatically start the SMB service. Ensure the
required services can be started and try again.
Command: %{command}
Stderr: %{stderr}
Stdout: %{stdout}
credentials_missing: |-
Vagrant SMB synced folders require the account password to be stored
in an NT compatible format. Please update your sharing settings to
enable a Windows compatible password and try again.
define_share_failed: |-
Exporting an SMB share failed! Details about the failure are shown
below. Please inspect the error message and correct any problems.

View File

@ -3,6 +3,8 @@ require_relative "../../../../base"
require_relative "../../../../../../plugins/hosts/darwin/cap/smb"
describe VagrantPlugins::HostDarwin::Cap::SMB do
include_context "unit"
let(:subject){ VagrantPlugins::HostDarwin::Cap::SMB }
let(:machine){ double(:machine) }
let(:env){ double(:env) }
@ -23,18 +25,61 @@ describe VagrantPlugins::HostDarwin::Cap::SMB do
end
end
describe ".smb_start" do
before{ allow(Vagrant::Util::Subprocess).to receive(:execute)
.and_return(result.new(0, "SMB-NT", "")) }
it "should check for NT compatible password" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with("pwpolicy", "gethashtypes").
and_return(result.new(0, "SMB-NT", ""))
subject.smb_start(env)
end
it "should raise error if NT compatible password is not set" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with("pwpolicy", "gethashtypes").
and_return(result.new(0, "", ""))
expect{ subject.smb_start(env) }.to raise_error(VagrantPlugins::SyncedFolderSMB::Errors::SMBCredentialsMissing)
end
it "should ignore if the command returns non-zero" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with("pwpolicy", "gethashtypes").
and_return(result.new(1, "", ""))
subject.smb_start(env)
end
it "should not load smb preferences if it is already loaded" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with("launchctl", "list", /preferences/).and_return(result.new(0, "", ""))
expect(Vagrant::Util::Subprocess).not_to receive(:execute).with(/sudo/, /launchctl/, "load", "-w", /preferences/)
subject.smb_start(env)
end
it "should load smb preferences if it is not already loaded" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with("launchctl", "list", /preferences/).and_return(result.new(1, "", ""))
expect(Vagrant::Util::Subprocess).to receive(:execute).with(/sudo/, /launchctl/, "load", "-w", /preferences/).and_return(result.new(0, "", ""))
subject.smb_start(env)
end
it "should raise error if load smb preferences fails" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with("launchctl", "list", /preferences/).and_return(result.new(1, "", ""))
expect(Vagrant::Util::Subprocess).to receive(:execute).with(/sudo/, /launchctl/, "load", "-w", /preferences/).and_return(result.new(1, "", ""))
expect{ subject.smb_start(env) }.to raise_error(VagrantPlugins::SyncedFolderSMB::Errors::SMBStartFailed)
end
# TODO Finish out last start coverage
end
describe ".smb_cleanup" do
after{ subject.smb_cleanup(env, machine, options) }
it "should search for shares with generated machine ID" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with(
anything, anything, /.*CUSTOM_ID.*/).and_return(result.new(0, "", ""))
"/usr/bin/sudo", /sharing/, "-l").and_return(result.new(0, "", ""))
end
it "should remove shares individually" do
expect(Vagrant::Util::Subprocess).to receive(:execute).
with(anything, anything, /.*CUSTOM_ID.*/).
and_return(result.new(0, "vgt-CUSTOM_ID-1\nvgt-CUSTOM_ID-2\n", ""))
with("/usr/bin/sudo", /sharing/, "-l").
and_return(result.new(0, "name: vgt-CUSTOM_ID-1\nname: vgt-CUSTOM_ID-2\n", ""))
expect(Vagrant::Util::Subprocess).to receive(:execute).with(/sudo/, /sharing/, anything, /CUSTOM_ID/).
twice.and_return(result.new(0, "", ""))
end

View File

@ -67,7 +67,7 @@ describe VagrantPlugins::SyncedFolderSMB::SyncedFolder do
end
describe ".prepare" do
let(:host_caps){ [:smb_prepare] }
let(:host_caps){ [:smb_start, :smb_prepare] }
context "without credentials provided" do
before do
@ -86,6 +86,11 @@ describe VagrantPlugins::SyncedFolderSMB::SyncedFolder do
expect(folders['/second/path'][:smb_username]).to eq('username')
expect(folders['/second/path'][:smb_password]).to eq('password')
end
it "should start the SMB service if capability is available" do
expect(host).to receive(:capability).with(:smb_install, any_args)
subject.prepare(machine, folders, options)
end
end
context "with credentials provided" do

View File

@ -56,7 +56,9 @@ without requiring a password each time:
Cmnd_Alias VAGRANT_SMB_ADD = /usr/sbin/sharing -a * -S * -s * -g * -n *
Cmnd_Alias VAGRANT_SMB_REMOVE = /usr/sbin/sharing -r *
Cmnd_Alias VAGRANT_SMB_LIST = /usr/sbin/sharing -l
%admin ALL=(root) NOPASSWD: VAGRANT_SMB_ADD, VAGRANT_SMB_REMOVE, VAGRANT_SMB_LIST
Cmnd_Alias VAGRANT_SMB_PSTART = /bin/launchctl load -w /System/Library/LaunchDaemons/com.apple.smb.preferences.plist
Cmnd_Alias VAGRANT_SMB_DSTART = /bin/launchctl load -w /System/Library/LaunchDaemons/com.apple.smb.preferences.plist
%admin ALL=(root) NOPASSWD: VAGRANT_SMB_ADD, VAGRANT_SMB_REMOVE, VAGRANT_SMB_LIST, VAGRANT_SMB_PSTART, VAGRANT_SMB_DSTART
```
### Guests