From a8d9402554bc82f077bcfacc6c96ef778f07965c Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Thu, 26 Apr 2012 14:13:20 -0700 Subject: [PATCH] Work around #3947, #4248, #14073; load our utility code Without this patch the registry module blows up when installed onto a Linux Puppet Master. The utility code and the structure of the types and providers end up requiring win32/registry which will never be present on non-windows systems. In addition, the types and providers mix in module level support code, which does not work because of the following Puppet bugs, all related to our inability to load utility code from the $LOAD_PATH. * https://projects.puppetlabs.com/issues/3947 * https://projects.puppetlabs.com/issues/4248 * https://projects.puppetlabs.com/issues/14073 This has annoyed me enough that I'm going revisit these bugs and the interplay of the modulepath, environments, and $LOAD_PATH. --- lib/puppet/modules/registry.rb | 10 ++- lib/puppet/modules/registry/key_path.rb | 17 ++++-- lib/puppet/modules/registry/registry_base.rb | 61 ++++++++++--------- lib/puppet/modules/registry/value_path.rb | 6 +- lib/puppet/provider/registry_key/registry.rb | 15 +++-- .../provider/registry_value/registry.rb | 14 +++-- lib/puppet/type/registry_key.rb | 7 ++- lib/puppet/type/registry_value.rb | 7 ++- 8 files changed, 83 insertions(+), 54 deletions(-) diff --git a/lib/puppet/modules/registry.rb b/lib/puppet/modules/registry.rb index 55a460f4..8876156d 100644 --- a/lib/puppet/modules/registry.rb +++ b/lib/puppet/modules/registry.rb @@ -1,4 +1,12 @@ -require 'puppet/modules' +require 'pathname' +# JJM WORK_AROUND +# explicitly require files without relying on $LOAD_PATH until #14073 is fixed. +# https://projects.puppetlabs.com/issues/14073 is fixed. +require Pathname.new(__FILE__).dirname.expand_path module Puppet::Modules::Registry + # For 64-bit OS, use 64-bit view. Ignored on 32-bit OS + KEY_WOW64_64KEY = 0x100 unless defined? KEY_WOW64_64KEY + # For 64-bit OS, use 32-bit view. Ignored on 32-bit OS + KEY_WOW64_32KEY = 0x200 unless defined? KEY_WOW64_32KEY end diff --git a/lib/puppet/modules/registry/key_path.rb b/lib/puppet/modules/registry/key_path.rb index 21182349..4d14fca4 100644 --- a/lib/puppet/modules/registry/key_path.rb +++ b/lib/puppet/modules/registry/key_path.rb @@ -1,5 +1,10 @@ require 'puppet/parameter' -require 'puppet/modules/registry/registry_base' +require 'pathname' +# JJM WORK_AROUND +# explicitly require files without relying on $LOAD_PATH until #14073 is fixed. +# https://projects.puppetlabs.com/issues/14073 is fixed. +require Pathname.new(__FILE__).dirname +require Pathname.new(__FILE__).dirname + 'registry_base' class Puppet::Modules::Registry::KeyPath < Puppet::Parameter include Puppet::Modules::Registry::RegistryBase @@ -11,10 +16,14 @@ def munge(path) raise ArgumentError, "Invalid registry key: #{path}" end - @access = (captures[1] and captures[1] == '32:') ? KEY_WOW64_32KEY : KEY_WOW64_64KEY + @access = if captures[1] == '32:' + Puppet::Modules::Registry::KEY_WOW64_32KEY + else + Puppet::Modules::Registry::KEY_WOW64_64KEY + end # canonical root key symbol - @root = case captures[2].downcase + @root = case captures[2].to_s.downcase when /hkey_local_machine/, /hklm/ :hklm when /hkey_classes_root/, /hkcr/ @@ -32,7 +41,7 @@ def munge(path) end # the hkey object for the root key - @hkey = HKEYS[root] + @hkey = hkeys[root] @subkey = captures[3] if @subkey.empty? diff --git a/lib/puppet/modules/registry/registry_base.rb b/lib/puppet/modules/registry/registry_base.rb index 5be071ca..e74d4cd0 100644 --- a/lib/puppet/modules/registry/registry_base.rb +++ b/lib/puppet/modules/registry/registry_base.rb @@ -1,46 +1,49 @@ -require 'puppet/modules/registry' +require 'pathname' # JJM WORK_AROUND #14073 +require Pathname.new(__FILE__).dirname.expand_path module Puppet::Modules::Registry::RegistryBase - require 'win32/registry' - - HKEYS = { - :hkcr => Win32::Registry::HKEY_CLASSES_ROOT, - :hklm => Win32::Registry::HKEY_LOCAL_MACHINE, - #:hku => Win32::Registry::HKEY_USERS, - #:hkcu => HKEY_CURRENT_USER, - } - - TYPE2NAME = { - Win32::Registry::REG_NONE => :none, - Win32::Registry::REG_SZ => :string, - Win32::Registry::REG_EXPAND_SZ => :expand, - Win32::Registry::REG_BINARY => :binary, - Win32::Registry::REG_DWORD => :dword, - Win32::Registry::REG_QWORD => :qword, - Win32::Registry::REG_MULTI_SZ => :array - } + if Puppet.features.microsoft_windows? + begin + require 'win32/registry' + rescue LoadError => exc + msg = "Could not load the required win32/registry library (ErrorID 1EAD86E3-D533-4286-BFCB-CCE8B818DDEA) [#{exc.message}]" + Puppet.err msg + error = Puppet::Error.new(msg) + error.set_backtrace exc.backtrace + raise error + end + end # REG_DWORD_BIG_ENDIAN REG_LINK # REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR # REG_RESOURCE_REQUIREMENTS_LIST - # For 64-bit OS, use 64-bit view. Ignored on 32-bit OS - KEY_WOW64_64KEY = 0x100 - # For 64-bit OS, use 32-bit view. Ignored on 32-bit OS - KEY_WOW64_32KEY = 0x200 - - NAME2TYPE = {} - TYPE2NAME.each_pair {|k,v| NAME2TYPE[v] = k} + def type2name_map + { + Win32::Registry::REG_NONE => :none, + Win32::Registry::REG_SZ => :string, + Win32::Registry::REG_EXPAND_SZ => :expand, + Win32::Registry::REG_BINARY => :binary, + Win32::Registry::REG_DWORD => :dword, + Win32::Registry::REG_QWORD => :qword, + Win32::Registry::REG_MULTI_SZ => :array + } + end def type2name(type) - return TYPE2NAME[type] + type2name_map[type] end def name2type(name) - return NAME2TYPE[name] + name2type = {} + type2name_map.each_pair {|k,v| name2type[v] = k} + name2type[name] end def hkeys - HKEYS + { + :hkcr => Win32::Registry::HKEY_CLASSES_ROOT, + :hklm => Win32::Registry::HKEY_LOCAL_MACHINE, + } end end diff --git a/lib/puppet/modules/registry/value_path.rb b/lib/puppet/modules/registry/value_path.rb index b2850e17..ed2e4be6 100644 --- a/lib/puppet/modules/registry/value_path.rb +++ b/lib/puppet/modules/registry/value_path.rb @@ -1,5 +1,9 @@ +require 'pathname' +# JJM WORK_AROUND +# explicitly require files without relying on $LOAD_PATH until #14073 is fixed. +# https://projects.puppetlabs.com/issues/14073 is fixed. +require Pathname.new(__FILE__).dirname.expand_path + 'key_path' require 'puppet/parameter' -require 'puppet/modules/registry/key_path' class Puppet::Modules::Registry::ValuePath < Puppet::Modules::Registry::KeyPath attr_reader :valuename diff --git a/lib/puppet/provider/registry_key/registry.rb b/lib/puppet/provider/registry_key/registry.rb index ad6e558b..dafa50fe 100644 --- a/lib/puppet/provider/registry_key/registry.rb +++ b/lib/puppet/provider/registry_key/registry.rb @@ -1,18 +1,16 @@ # REMIND: need to support recursive delete of subkeys & values Puppet::Type.type(:registry_key).provide(:registry) do - require 'puppet/modules/registry/registry_base' - include Puppet::Modules::Registry::RegistryBase + require 'pathname' # JJM WORK_AROUND #14073 + require Pathname.new(__FILE__).dirname.dirname.dirname.expand_path + 'modules/registry/registry_base' + extend Puppet::Modules::Registry::RegistryBase defaultfor :operatingsystem => :windows confine :operatingsystem => :windows - RegDeleteKeyEx = Win32API.new('advapi32', 'RegDeleteKeyEx', 'LPLL', 'L') - def self.instances - self::HKEYS.keys.collect do |hkey| - new(:provider => :registry, - :name => "#{hkey.to_s}") + hkeys.keys.collect do |hkey| + new(:provider => :registry, :name => "#{hkey.to_s}") end end @@ -30,8 +28,9 @@ def destroy Puppet.debug("destroy key #{resource[:path]}") raise "Cannot delete root key: #{resource[:path]}" unless keypath.subkey + reg_delete_key_ex = Win32API.new('advapi32', 'RegDeleteKeyEx', 'LPLL', 'L') - if RegDeleteKeyEx.call(keypath.hkey.hkey, keypath.subkey, keypath.access, 0) != 0 + if reg_delete_key_ex.call(keypath.hkey.hkey, keypath.subkey, keypath.access, 0) != 0 raise "Failed to delete registry key: #{resource[:path]}" end end diff --git a/lib/puppet/provider/registry_value/registry.rb b/lib/puppet/provider/registry_value/registry.rb index be98c6be..3c8a5320 100644 --- a/lib/puppet/provider/registry_value/registry.rb +++ b/lib/puppet/provider/registry_value/registry.rb @@ -1,12 +1,12 @@ +require 'puppet/type' Puppet::Type.type(:registry_value).provide(:registry) do - require 'puppet/modules/registry/registry_base' + require 'pathname' # JJM WORK_AROUND #14073 + require Pathname.new(__FILE__).dirname.dirname.dirname.expand_path + 'modules/registry/registry_base' include Puppet::Modules::Registry::RegistryBase defaultfor :operatingsystem => :windows confine :operatingsystem => :windows - RegQueryValueExA = Win32API.new('advapi32', 'RegQueryValueEx', 'LPLPPP', 'L') - def self.instances [] end @@ -27,7 +27,7 @@ def exists? valuepath.hkey.open(valuepath.subkey, Win32::Registry::KEY_READ | valuepath.access) do |reg| type = [0].pack('L') size = [0].pack('L') - found = RegQueryValueExA.call(reg.hkey, valuepath.valuename, 0, type, 0, size) == 0 + found = reg_query_value_ex_a.call(reg.hkey, valuepath.valuename, 0, type, 0, size) == 0 end found end @@ -74,7 +74,7 @@ def regvalue type = [0].pack('L') size = [0].pack('L') - if RegQueryValueExA.call(reg.hkey, valuepath.valuename, 0, type, 0, size) == 0 + if reg_query_value_ex_a.call(reg.hkey, valuepath.valuename, 0, type, 0, size) == 0 @regvalue[:type], @regvalue[:data] = from_native(reg.read(valuepath.valuename)) end end @@ -114,6 +114,10 @@ def from_native(ary) return [type2name(ntype), pdata] end + def reg_query_value_ex_a + @@reg_query_value_ex_a ||= Win32API.new('advapi32', 'RegQueryValueEx', 'LPLPPP', 'L') + end + # def to_s # "#{valuepath.hkey.keyname}\\#{valuepath.subkey}\\#{valuepath.valuename}" # end diff --git a/lib/puppet/type/registry_key.rb b/lib/puppet/type/registry_key.rb index 85ec0c26..7d88e901 100644 --- a/lib/puppet/type/registry_key.rb +++ b/lib/puppet/type/registry_key.rb @@ -1,7 +1,8 @@ -require 'puppet/modules/registry/registry_base' -require 'puppet/modules/registry/key_path' - +require 'puppet/type' Puppet::Type.newtype(:registry_key) do + require 'pathname' # JJM WORK_AROUND #14073 + require Pathname.new(__FILE__).dirname.dirname.expand_path + 'modules/registry/registry_base' + require Pathname.new(__FILE__).dirname.dirname.expand_path + 'modules/registry/key_path' include Puppet::Modules::Registry::RegistryBase def self.title_patterns diff --git a/lib/puppet/type/registry_value.rb b/lib/puppet/type/registry_value.rb index 5508e7c2..619cddd0 100644 --- a/lib/puppet/type/registry_value.rb +++ b/lib/puppet/type/registry_value.rb @@ -1,7 +1,8 @@ -require 'puppet/modules/registry/registry_base' -require 'puppet/modules/registry/value_path' - +require 'puppet/type' Puppet::Type.newtype(:registry_value) do + require 'pathname' # JJM WORK_AROUND #14073 + require Pathname.new(__FILE__).dirname.dirname.expand_path + 'modules/registry/registry_base' + require Pathname.new(__FILE__).dirname.dirname.expand_path + 'modules/registry/value_path' include Puppet::Modules::Registry::RegistryBase def self.title_patterns