Skip to content
This repository has been archived by the owner on Aug 18, 2022. It is now read-only.

Commit

Permalink
(MODULES-2175) Handle symlink missing target path
Browse files Browse the repository at this point in the history
When the target for a symlink no longer exists, attempting to unlink
the symlink with `Puppet::FileSystem.unlink` fails with a `Permission
Denied` error. If the target path doesn't exist, fall back to moving
the existing link in the same way we would if it were a file or
directory.
  • Loading branch information
ferventcoder committed Aug 10, 2015
1 parent 7523d5b commit cc91b35
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 6 deletions.
17 changes: 15 additions & 2 deletions lib/puppet/feature/vendors_dsc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,29 @@ def self.set_symlink_folder
Puppet::FileSystem.readlink(puppet_modules_vendor_folder) == vendored_modules_path

if Puppet::FileSystem.symlink?(puppet_modules_vendor_folder)
Puppet::FileSystem.unlink(puppet_modules_vendor_folder)
begin
Puppet::FileSystem.unlink(puppet_modules_vendor_folder)
rescue => e
# If the target path doesn't exist, unlinking will fail.
# Instead prefer to move the path so the link creation
# can occur successfully.
Puppet.warning "Error occurred attempting to remove old symlink. It's likely the target path no longer exists. Renaming the link instead."
append_location_with_current_date_time puppet_modules_vendor_folder
end
elsif Puppet::FileSystem.exist?(puppet_modules_vendor_folder)
FileUtils.mv puppet_modules_vendor_folder, "#{puppet_modules_vendor_folder}.#{Time.now.utc.strftime("%Y%m%d_%H%M%S_%L")}"
append_location_with_current_date_time puppet_modules_vendor_folder
end

Puppet.debug "Creating symlink at '#{puppet_modules_vendor_folder}' \n pointed to '#{vendored_modules_path}'."
Puppet::FileSystem.dir_mkpath(puppet_modules_vendor_folder) if !Puppet::FileSystem.dir_exist?(puppet_modules_vendor_folder)
Puppet::FileSystem.symlink(vendored_modules_path, puppet_modules_vendor_folder,{ :force => true})
end

# Add the current date time as a string to the end of an existing location.
def self.append_location_with_current_date_time(existing_location)
FileUtils.mv existing_location, "#{existing_location}.#{Time.now.utc.strftime("%Y%m%d_%H%M%S_%L")}"
end

# Get the non-x86 program files path, no matter whether the process is
# a 32 bit or 64 bit process. Shut off registry redirection and query
# the ProgramFilesDir key to retrieve the program files value.
Expand Down
17 changes: 13 additions & 4 deletions spec/integration/puppet/feature/vendors_dsc_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,28 @@ def set_symlink_and_check
end

it "should recreate a symlink if the existing link path is wrong" do
FileUtils.mkdir_p(program_files)
Puppet::FileSystem.symlink(subject.vendored_modules_path, Dir.mktmpdir('dsc_link'), { :force => true})
FileUtils.mkdir_p(::File.expand_path('..', vendored_modules_symlink_path))
Puppet::FileSystem.symlink(Dir.mktmpdir('dsc_link'), vendored_modules_symlink_path, { :force => true})

set_symlink_and_check
end

it "should recreate a symlink if the existing link path does not exist" do
FileUtils.mkdir_p(::File.expand_path('..', vendored_modules_symlink_path))
link_target = Dir.mktmpdir('dsc_link')
Puppet::FileSystem.symlink(link_target, vendored_modules_symlink_path, { :force => true})
system("rmdir /s /q \"#{link_target}\"")

set_symlink_and_check
end

it "should recreate a symlink if the existing path is a directory" do
it "should create a symlink if the existing path is a directory" do
FileUtils.mkdir_p(vendored_modules_symlink_path)

set_symlink_and_check
end

it "should recreate a symlink if the existing path is a file" do
it "should create a symlink if the existing path is a file" do
FileUtils.mkdir_p(::File.expand_path('..', vendored_modules_symlink_path))
FileUtils.touch vendored_modules_symlink_path

Expand Down
14 changes: 14 additions & 0 deletions spec/unit/puppet/feature/vendors_dsc_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ module DscSymlink; end # for tests on non-Windows
subject.set_symlink_folder
end

it "should recreate a symlink if the existing link path does not exist" do
Puppet::FileSystem.expects(:symlink?).returns(true).times(2)
Puppet::FileSystem.expects(:readlink).returns('C:\dsc')
Puppet::FileSystem.expects(:unlink).raises(StandardError.new(3),'Permission denied')
FileUtils.expects(:mv)
Puppet::FileSystem.expects(:dir_exist?).returns(true)
Puppet::FileSystem.expects(:symlink)

Puppet::FileSystem.expects(:exist?).never
Puppet::FileSystem.expects(:dir_mkpath).never

subject.set_symlink_folder
end

it "should create a symlink if the existing path is not a symlink" do
Puppet::FileSystem.expects(:symlink?).returns(false).times(2)
Puppet::FileSystem.expects(:exist?).returns(true)
Expand Down

0 comments on commit cc91b35

Please sign in to comment.