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_ADD = /usr/sbin/sharing -a * -S * -s * -g * -n *
Cmnd_Alias VAGRANT_SMB_REMOVE = /usr/sbin/sharing -r * Cmnd_Alias VAGRANT_SMB_REMOVE = /usr/sbin/sharing -r *
Cmnd_Alias VAGRANT_SMB_LIST = /usr/sbin/sharing -l 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") File.exist?("/usr/sbin/sharing")
end 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 # Required options for mounting a share hosted
# on macos. # on macos.
def self.smb_mount_options(env) def self.smb_mount_options(env)

View File

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

View File

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

View File

@ -30,6 +30,11 @@ module VagrantPlugins
def prepare(machine, folders, opts) def prepare(machine, folders, opts)
machine.ui.output(I18n.t("vagrant_sf_smb.preparing")) 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 smb_username = smb_password = nil
# If we need auth information, then ask the user. # If we need auth information, then ask the user.

View File

@ -1,9 +1,10 @@
en: en:
vagrant_sf_smb: vagrant_sf_smb:
not_supported: |- not_supported: |-
It appears your machine doesn't support SMB, or there is not an It appears your machine doesn't support SMB, has not been
adapter to enable SMB on this machine for Vagrant. Ensure SMB properly configured for SMB, or there is not an adapter to
host functionality is available on this machine and try again. enable SMB on this machine for Vagrant. Ensure SMB host
functionality is available on this machine and try again.
mounting: |- mounting: |-
Mounting SMB shared folders... Mounting SMB shared folders...
mounting_single: |- mounting_single: |-
@ -23,6 +24,19 @@ en:
Vagrant requires administator access to create SMB shares and Vagrant requires administator access to create SMB shares and
may request access to complete setup of configured shares. may request access to complete setup of configured shares.
errors: 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: |- define_share_failed: |-
Exporting an SMB share failed! Details about the failure are shown Exporting an SMB share failed! Details about the failure are shown
below. Please inspect the error message and correct any problems. 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" require_relative "../../../../../../plugins/hosts/darwin/cap/smb"
describe VagrantPlugins::HostDarwin::Cap::SMB do describe VagrantPlugins::HostDarwin::Cap::SMB do
include_context "unit"
let(:subject){ VagrantPlugins::HostDarwin::Cap::SMB } let(:subject){ VagrantPlugins::HostDarwin::Cap::SMB }
let(:machine){ double(:machine) } let(:machine){ double(:machine) }
let(:env){ double(:env) } let(:env){ double(:env) }
@ -23,18 +25,61 @@ describe VagrantPlugins::HostDarwin::Cap::SMB do
end end
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 describe ".smb_cleanup" do
after{ subject.smb_cleanup(env, machine, options) } after{ subject.smb_cleanup(env, machine, options) }
it "should search for shares with generated machine ID" do it "should search for shares with generated machine ID" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with( 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 end
it "should remove shares individually" do it "should remove shares individually" do
expect(Vagrant::Util::Subprocess).to receive(:execute). expect(Vagrant::Util::Subprocess).to receive(:execute).
with(anything, anything, /.*CUSTOM_ID.*/). with("/usr/bin/sudo", /sharing/, "-l").
and_return(result.new(0, "vgt-CUSTOM_ID-1\nvgt-CUSTOM_ID-2\n", "")) 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/). expect(Vagrant::Util::Subprocess).to receive(:execute).with(/sudo/, /sharing/, anything, /CUSTOM_ID/).
twice.and_return(result.new(0, "", "")) twice.and_return(result.new(0, "", ""))
end end

View File

@ -67,7 +67,7 @@ describe VagrantPlugins::SyncedFolderSMB::SyncedFolder do
end end
describe ".prepare" do describe ".prepare" do
let(:host_caps){ [:smb_prepare] } let(:host_caps){ [:smb_start, :smb_prepare] }
context "without credentials provided" do context "without credentials provided" do
before 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_username]).to eq('username')
expect(folders['/second/path'][:smb_password]).to eq('password') expect(folders['/second/path'][:smb_password]).to eq('password')
end 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 end
context "with credentials provided" do 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_ADD = /usr/sbin/sharing -a * -S * -s * -g * -n *
Cmnd_Alias VAGRANT_SMB_REMOVE = /usr/sbin/sharing -r * Cmnd_Alias VAGRANT_SMB_REMOVE = /usr/sbin/sharing -r *
Cmnd_Alias VAGRANT_SMB_LIST = /usr/sbin/sharing -l 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 ### Guests