From 120722ab08db846e65a59d450d4a6091ec6208ad Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Thu, 14 Dec 2017 08:28:11 -0800 Subject: [PATCH] Update NFS service name usage for linux hosts Provides simple nfs service name detection via systemd or sys-v. Defaults are provided if no match is found. Service name is defined via method allowing derivative guests to only need to provide an updated name. --- plugins/hosts/linux/cap/nfs.rb | 45 ++++++++++++++-- test/unit/plugins/hosts/linux/cap/nfs_test.rb | 51 ++++++++++++++++++- 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/plugins/hosts/linux/cap/nfs.rb b/plugins/hosts/linux/cap/nfs.rb index c4743c774..1d407d52e 100644 --- a/plugins/hosts/linux/cap/nfs.rb +++ b/plugins/hosts/linux/cap/nfs.rb @@ -9,25 +9,53 @@ module VagrantPlugins class NFS NFS_EXPORTS_PATH = "/etc/exports".freeze + NFS_DEFAULT_NAME_SYSTEMD = "nfs-server.service".freeze + NFS_DEFAULT_NAME_SYSV = "nfs-kernel-server".freeze extend Vagrant::Util::Retryable + def self.nfs_service_name_systemd + if !defined?(@_nfs_systemd) + result = Vagrant::Util::Subprocess.execute("systemctl", "list-units", + "*nfs*server*", "--no-pager", "--no-legend") + if result.exit_code == 0 + @_nfs_systemd = result.stdout.to_s.split(/\s+/).first + end + if @_nfs_systemd.to_s.empty? + @_nfs_systemd = NFS_DEFAULT_NAME_SYSTEMD + end + end + @_nfs_systemd + end + + def self.nfs_service_name_sysv + if !defined?(@_nfs_sysv) + @_nfs_sysv = Dir.glob("/etc/init.d/*nfs*server*").first.to_s + if @_nfs_sysv.empty? + @_nfs_sysv = NFS_DEFAULT_NAME_SYSV + else + @_nfs_sysv = File.basename(@_nfs_sysv) + end + end + @_nfs_sysv + end + def self.nfs_apply_command(env) "exportfs -ar" end def self.nfs_check_command(env) if Vagrant::Util::Platform.systemd? - "systemctl status --no-pager nfs-server.service" + "systemctl status --no-pager #{nfs_service_name_systemd}" else - "/etc/init.d/nfs-kernel-server status" + "/etc/init.d/#{nfs_service_name_sysv} status" end end def self.nfs_start_command(env) if Vagrant::Util::Platform.systemd? - "systemctl start nfs-server.service" + "systemctl start #{nfs_service_name_systemd}" else - "/etc/init.d/nfs-kernel-server start" + "/etc/init.d/#{nfs_service_name_sysv} start" end end @@ -63,7 +91,7 @@ module VagrantPlugins if Vagrant::Util::Platform.systemd? Vagrant::Util::Subprocess.execute("/bin/sh", "-c", "systemctl --no-pager --no-legend --plain list-unit-files --all --type=service " \ - "| grep nfs-server.service").exit_code == 0 + "| grep #{nfs_service_name_systemd}").exit_code == 0 else Vagrant::Util::Subprocess.execute("modinfo", "nfsd").exit_code == 0 || Vagrant::Util::Subprocess.execute("grep", "nfsd", "/proc/filesystems").exit_code == 0 @@ -233,6 +261,13 @@ module VagrantPlugins def self.nfs_running?(check_command) Vagrant::Util::Subprocess.execute(*Shellwords.split(check_command)).exit_code == 0 end + + # @private + # Reset the cached values for capability. This is not considered a public + # API and should only be used for testing. + def self.reset! + instance_variables.each(&method(:remove_instance_variable)) + end end end end diff --git a/test/unit/plugins/hosts/linux/cap/nfs_test.rb b/test/unit/plugins/hosts/linux/cap/nfs_test.rb index bb8ca9079..144041924 100644 --- a/test/unit/plugins/hosts/linux/cap/nfs_test.rb +++ b/test/unit/plugins/hosts/linux/cap/nfs_test.rb @@ -24,15 +24,58 @@ describe VagrantPlugins::HostLinux::Cap::NFS do @original_exports_path = VagrantPlugins::HostLinux::Cap::NFS::NFS_EXPORTS_PATH VagrantPlugins::HostLinux::Cap::NFS.send(:remove_const, :NFS_EXPORTS_PATH) VagrantPlugins::HostLinux::Cap::NFS.const_set(:NFS_EXPORTS_PATH, tmp_exports_path.to_s) + allow(Vagrant::Util::Subprocess).to receive(:execute).with("systemctl", "list-units", any_args). + and_return(Vagrant::Util::Subprocess::Result.new(1, "", "")) + allow(Vagrant::Util::Platform).to receive(:systemd?).and_return(false) end after do VagrantPlugins::HostLinux::Cap::NFS.send(:remove_const, :NFS_EXPORTS_PATH) VagrantPlugins::HostLinux::Cap::NFS.const_set(:NFS_EXPORTS_PATH, @original_exports_path) + VagrantPlugins::HostLinux::Cap::NFS.reset! File.unlink(tmp_exports_path.to_s) if File.exist?(tmp_exports_path.to_s) @tmp_exports = nil end + describe ".nfs_service_name_systemd" do + let(:cap){ VagrantPlugins::HostLinux::Cap::NFS } + + context "without service match" do + it "should use default service name" do + expect(cap.nfs_service_name_systemd).to eq(cap.const_get(:NFS_DEFAULT_NAME_SYSTEMD)) + end + end + + context "with service match" do + let(:custom_nfs_service_name){ "custom-nfs-server-service-name" } + before{ expect(Vagrant::Util::Subprocess).to receive(:execute).with("systemctl", "list-units", any_args). + and_return(Vagrant::Util::Subprocess::Result.new(0, custom_nfs_service_name, "")) } + + it "should use the matched service name" do + expect(cap.nfs_service_name_systemd).to eq(custom_nfs_service_name) + end + end + end + + describe ".nfs_service_name_sysv" do + let(:cap){ VagrantPlugins::HostLinux::Cap::NFS } + + context "without service match" do + it "should use default service name" do + expect(cap.nfs_service_name_sysv).to eq(cap.const_get(:NFS_DEFAULT_NAME_SYSV)) + end + end + + context "with service match" do + let(:custom_nfs_service_name){ "/etc/init.d/custom-nfs-server-service-name" } + before{ expect(Dir).to receive(:glob).with(/.+init\.d.+/).and_return([custom_nfs_service_name]) } + + it "should use the matched service name" do + expect(cap.nfs_service_name_sysv).to eq(File.basename(custom_nfs_service_name)) + end + end + end + describe ".nfs_check_command" do let(:cap){ caps.get(:nfs_check_command) } @@ -44,7 +87,9 @@ describe VagrantPlugins::HostLinux::Cap::NFS do end end context "with systemd" do - before{ expect(Vagrant::Util::Platform).to receive(:systemd?).and_return(true) } + before do + expect(Vagrant::Util::Platform).to receive(:systemd?).and_return(true) + end it "should use systemctl" do expect(cap.nfs_check_command(env)).to include("systemctl") @@ -162,6 +207,8 @@ EOH before do allow(ui).to receive(:info) + allow(Vagrant::Util::Subprocess).to receive(:execute).with("mv", any_args). + and_call_original end it "should remove entries no longer valid" do @@ -189,6 +236,8 @@ EOH before do File.write(tmp_exports_path, "original content") + allow(Vagrant::Util::Subprocess).to receive(:execute).with("mv", any_args). + and_call_original end it "should write updated contents to file" do