Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(SDK-268) Create directory junctions instead of symlinks on windows #192

Merged
merged 1 commit into from
Jun 7, 2017

Conversation

rodjek
Copy link
Contributor

@rodjek rodjek commented Jun 6, 2017

Expands on the windows symlink functionality by falling back to using directory junctions if Puppet::FileSystem.symlink fails to create the symlink (or isn't available). Unlike symlinks, NTFS junctions don't require administrator access 🎉 and provide identical behaviour for our purposes.

As Puppet::FileSystem.symlink doesn't raise an exception when run as non-administrator, we can just check for the existence of the link target after it (File.symlink? conveniently returns true for junctions) in order to fall back to using junctions.

The win32-dir gem extends Dir with a create_junction method that we try to use first. If that gem isn't available then we fall back to shelling out to mklink to create the junction.

@puppetcla
Copy link

CLA signed by all contributors.

@DavidS
Copy link
Contributor

DavidS commented Jun 6, 2017

it looks like the symlink code does error on Windows:

PS C:\vagrant\testmodule> bundle exec rake spec_prep
rake aborted!
Puppet::Util::Windows::Error: CreateSymbolicLink(spec/fixtures/modules/C:\vagrant\testmodule, C:\vagrant\testmodule, 1):
  The filename, directory name, or volume label syntax is incorrect.
C:/Users/vagrant/gems/ruby/2.3.0/gems/puppet-4.8.1-x64-mingw32/lib/puppet/util/windows/file.rb:87:in `symlink'
C:/Users/vagrant/gems/ruby/2.3.0/gems/puppet-4.8.1-x64-mingw32/lib/puppet/file_system/windows.rb:44:in `symlink'
C:/Users/vagrant/gems/ruby/2.3.0/gems/puppet-4.8.1-x64-mingw32/lib/puppet/file_system.rb:251:in `symlink'
C:/Users/vagrant/gems/ruby/2.3.0/bundler/gems/puppetlabs_spec_helper-285222104625/lib/puppetlabs_spec_helper/rake_tasks.rb:294:in `block (2 levels) in <top (required)>'
C:/Users/vagrant/gems/ruby/2.3.0/bundler/gems/puppetlabs_spec_helper-285222104625/lib/puppetlabs_spec_helper/rake_tasks.rb:291:in `each'
C:/Users/vagrant/gems/ruby/2.3.0/bundler/gems/puppetlabs_spec_helper-285222104625/lib/puppetlabs_spec_helper/rake_tasks.rb:291:in `block in <top (required)>'
C:/Users/vagrant/gems/ruby/2.3.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)>'
Tasks: TOP => spec_prep
(See full trace by running task with --trace)
PS C:\vagrant\testmodule>

this is running this code against a repo with no .fixtures.yml. Maybe that's a 2.1 vs 2.3 distinction, but that won't save us long-term.

@rodjek
Copy link
Contributor Author

rodjek commented Jun 7, 2017

Hmm, it doesn't error for me on Ruby 2.3, but I am using Puppet 4.10.1 for testing. Will investigate further (it's an easy enough fix to catch the exception above, but i'm curious why it doesn't get raised on my VM)

rodjek added a commit to rodjek/puppet that referenced this pull request Jun 7, 2017
I was tracking down why CreateSymbolicLinkW was returning non-zero when
failing on one test VM and not a different one
(puppetlabs/puppetlabs_spec_helper#192).

Turns out CreateSymbolicLinkW returns a `BOOLEAN` (1 byte) rather than a
`BOOL` (4 bytes), so I was getting random garbage in the upper 3 bytes
and therefore a non-zero result.
@rodjek
Copy link
Contributor Author

rodjek commented Jun 7, 2017

Found the cause and it looks like a valid bug in Puppet, so time well spent.

@DavidS DavidS merged commit f55bcb9 into puppetlabs:master Jun 7, 2017
rodjek added a commit to rodjek/puppet that referenced this pull request Jun 7, 2017
I was tracking down why CreateSymbolicLinkW was returning non-zero when
failing on one test VM and not a different one
(puppetlabs/puppetlabs_spec_helper#192).

Turns out CreateSymbolicLinkW returns a `BOOLEAN` (1 byte) rather than a
`BOOL` (4 bytes), so I was getting random garbage in the upper 3 bytes
and therefore a non-zero result.
if is_windows
fail "Cannot symlink on Windows unless using at least Puppet 3.5" if !puppet_symlink_available
Puppet::FileSystem::exist?(target) || Puppet::FileSystem::symlink(source, target)
unless File.symlink(target)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean File.symlink? here?

This may have been fixed in later Ruby versions, but IIRC, symlink support was pretty broken in Ruby on Windows in earlier versions.

Iristyle pushed a commit to Iristyle/puppet that referenced this pull request Jun 7, 2017
 - CreateSymbolicLinkW was intermittently returning non-zero on
   different tests hosts, under similar circumstances.

   Some discussion in:
   puppetlabs/puppetlabs_spec_helper#192

 - The signature for CreateSymbolicLinkW should return a BOOLEAN
   (BYTE - aka unsigned char) value not a BOOL (4 byte / 32-bit
   signed int).

   Based on the presence of random data in the incorrectly sized
   return value, the code may behave incorrectly.

 - Fix the problem by sizing the return value correctly
Iristyle pushed a commit to Iristyle/puppet that referenced this pull request Jun 7, 2017
 - CreateSymbolicLinkW was intermittently returning non-zero on
   different tests hosts, under similar circumstances.

   Some discussion in:
   puppetlabs/puppetlabs_spec_helper#192

   Note the original PR was wrong and updated in:
   puppetlabs/puppetlabs_spec_helper@bb46874

 - The signature for CreateSymbolicLinkW should return a BOOLEAN
   (BYTE - aka unsigned char) value not a BOOL (4 byte / 32-bit
   signed int).

   Based on the presence of random data in the incorrectly sized
   return value, the code may behave incorrectly.

 - Fix the problem by sizing the return value correctly
@rodjek rodjek deleted the sdk-268 branch June 17, 2017 22:59
eputnam pushed a commit to eputnam/puppet that referenced this pull request Jul 12, 2017
 - CreateSymbolicLinkW was intermittently returning non-zero on
   different tests hosts, under similar circumstances.

   Some discussion in:
   puppetlabs/puppetlabs_spec_helper#192

   Note the original PR was wrong and updated in:
   puppetlabs/puppetlabs_spec_helper@bb46874

 - The signature for CreateSymbolicLinkW should return a BOOLEAN
   (BYTE - aka unsigned char) value not a BOOL (4 byte / 32-bit
   signed int).

   Based on the presence of random data in the incorrectly sized
   return value, the code may behave incorrectly.

 - Fix the problem by sizing the return value correctly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants