puppet 7.12.1-universal-darwin → 7.15.0-universal-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +1 -1
  3. data/Gemfile +2 -2
  4. data/Gemfile.lock +36 -31
  5. data/ext/project_data.yaml +1 -1
  6. data/lib/puppet/application/lookup.rb +74 -24
  7. data/lib/puppet/concurrent/thread_local_singleton.rb +5 -3
  8. data/lib/puppet/configurer.rb +8 -14
  9. data/lib/puppet/defaults.rb +13 -1
  10. data/lib/puppet/face/generate.rb +2 -0
  11. data/lib/puppet/file_serving/metadata.rb +3 -0
  12. data/lib/puppet/file_system/file_impl.rb +7 -7
  13. data/lib/puppet/file_system/jruby.rb +1 -1
  14. data/lib/puppet/file_system/path_pattern.rb +10 -15
  15. data/lib/puppet/file_system/uniquefile.rb +1 -1
  16. data/lib/puppet/file_system/windows.rb +4 -4
  17. data/lib/puppet/file_system.rb +1 -1
  18. data/lib/puppet/functions/next.rb +18 -1
  19. data/lib/puppet/functions/tree_each.rb +0 -1
  20. data/lib/puppet/functions/versioncmp.rb +6 -2
  21. data/lib/puppet/generate/type.rb +9 -0
  22. data/lib/puppet/graph/simple_graph.rb +2 -1
  23. data/lib/puppet/http/client.rb +1 -1
  24. data/lib/puppet/node.rb +1 -1
  25. data/lib/puppet/pops/parser/code_merger.rb +4 -4
  26. data/lib/puppet/pops/parser/egrammar.ra +2 -0
  27. data/lib/puppet/pops/parser/eparser.rb +574 -558
  28. data/lib/puppet/pops/serialization/to_data_converter.rb +6 -18
  29. data/lib/puppet/pops/validation/checker4_0.rb +7 -2
  30. data/lib/puppet/provider/service/init.rb +5 -4
  31. data/lib/puppet/resource/type_collection.rb +21 -17
  32. data/lib/puppet/ssl/verifier.rb +3 -1
  33. data/lib/puppet/transaction/persistence.rb +22 -12
  34. data/lib/puppet/type/exec.rb +1 -1
  35. data/lib/puppet/type/file/data_sync.rb +1 -1
  36. data/lib/puppet/type/file/group.rb +8 -1
  37. data/lib/puppet/type/file/owner.rb +8 -1
  38. data/lib/puppet/type/user.rb +41 -39
  39. data/lib/puppet/util/json.rb +17 -0
  40. data/lib/puppet/util/log.rb +7 -2
  41. data/lib/puppet/util/monkey_patches.rb +26 -4
  42. data/lib/puppet/util/package.rb +25 -16
  43. data/lib/puppet/util/yaml.rb +16 -1
  44. data/lib/puppet/util.rb +1 -0
  45. data/lib/puppet/version.rb +1 -1
  46. data/lib/puppet.rb +1 -0
  47. data/locales/puppet.pot +5 -9741
  48. data/man/man5/puppet.conf.5 +21 -2
  49. data/man/man8/puppet-agent.8 +1 -1
  50. data/man/man8/puppet-apply.8 +1 -1
  51. data/man/man8/puppet-catalog.8 +1 -1
  52. data/man/man8/puppet-config.8 +1 -1
  53. data/man/man8/puppet-describe.8 +1 -1
  54. data/man/man8/puppet-device.8 +1 -1
  55. data/man/man8/puppet-doc.8 +1 -1
  56. data/man/man8/puppet-epp.8 +1 -1
  57. data/man/man8/puppet-facts.8 +1 -1
  58. data/man/man8/puppet-filebucket.8 +1 -1
  59. data/man/man8/puppet-generate.8 +1 -1
  60. data/man/man8/puppet-help.8 +1 -1
  61. data/man/man8/puppet-lookup.8 +9 -6
  62. data/man/man8/puppet-module.8 +1 -1
  63. data/man/man8/puppet-node.8 +1 -1
  64. data/man/man8/puppet-parser.8 +1 -1
  65. data/man/man8/puppet-plugin.8 +1 -1
  66. data/man/man8/puppet-report.8 +1 -1
  67. data/man/man8/puppet-resource.8 +1 -1
  68. data/man/man8/puppet-script.8 +1 -1
  69. data/man/man8/puppet-ssl.8 +1 -1
  70. data/man/man8/puppet.8 +2 -2
  71. data/spec/fixtures/unit/forge/bacula.json +1 -1
  72. data/spec/integration/application/lookup_spec.rb +81 -50
  73. data/spec/integration/application/resource_spec.rb +6 -2
  74. data/spec/integration/parser/pcore_resource_spec.rb +10 -0
  75. data/spec/shared_contexts/l10n.rb +5 -0
  76. data/spec/unit/application/lookup_spec.rb +131 -10
  77. data/spec/unit/concurrent/thread_local_singleton_spec.rb +39 -0
  78. data/spec/unit/configurer_spec.rb +124 -61
  79. data/spec/unit/confiner_spec.rb +6 -6
  80. data/spec/unit/face/generate_spec.rb +64 -0
  81. data/spec/unit/file_system/uniquefile_spec.rb +7 -1
  82. data/spec/unit/file_system_spec.rb +34 -4
  83. data/spec/unit/forge/module_release_spec.rb +3 -3
  84. data/spec/unit/functions/versioncmp_spec.rb +40 -4
  85. data/spec/unit/node_spec.rb +6 -0
  86. data/spec/unit/pops/parser/parse_containers_spec.rb +2 -2
  87. data/spec/unit/pops/serialization/to_from_hr_spec.rb +0 -58
  88. data/spec/unit/pops/validator/validator_spec.rb +5 -0
  89. data/spec/unit/provider/service/gentoo_spec.rb +6 -5
  90. data/spec/unit/provider/service/init_spec.rb +15 -9
  91. data/spec/unit/provider/service/openwrt_spec.rb +21 -29
  92. data/spec/unit/provider/service/redhat_spec.rb +3 -2
  93. data/spec/unit/transaction/persistence_spec.rb +51 -0
  94. data/spec/unit/type/file/group_spec.rb +7 -0
  95. data/spec/unit/type/file/owner_spec.rb +7 -0
  96. data/spec/unit/type/user_spec.rb +67 -45
  97. data/spec/unit/util/json_spec.rb +126 -0
  98. data/spec/unit/util/windows_spec.rb +23 -0
  99. data/spec/unit/util/yaml_spec.rb +37 -13
  100. metadata +17 -5
@@ -14,8 +14,6 @@ module Serialization
14
14
  # @option options [Boolean] :local_reference use local references instead of duplicating complex entries
15
15
  # @option options [Boolean] :type_by_reference `true` if Object types are converted to references rather than embedded.
16
16
  # @option options [Boolean] :symbol_as_string `true` if Symbols should be converted to strings (with type loss)
17
- # @option options [Boolean] :force_symbol `false` if Symbols should not be converted (rich_data and symbol_as_string must be false)
18
- # @option options [Boolean] :silence_warnings `false` if warnings should be silenced
19
17
  # @option options [String] :message_prefix String to prepend to in warnings and errors
20
18
  # @return [Data] the processed result. An object assignable to `Data`.
21
19
  #
@@ -43,12 +41,6 @@ module Serialization
43
41
  @symbol_as_string = options[:symbol_as_string]
44
42
  @symbol_as_string = false if @symbol_as_string.nil?
45
43
 
46
- @force_symbol = options[:force_symbol]
47
- @force_symbol = false if @force_symbol.nil?
48
-
49
- @silence_warnings = options[:silence_warnings]
50
- @silence_warnings = false if @silence_warnings.nil?
51
-
52
44
  @rich_data = options[:rich_data]
53
45
  @rich_data = false if @rich_data.nil?
54
46
 
@@ -100,11 +92,7 @@ module Serialization
100
92
  elsif @rich_data
101
93
  { PCORE_TYPE_KEY => PCORE_TYPE_SYMBOL, PCORE_VALUE_KEY => value.to_s }
102
94
  else
103
- if @force_symbol
104
- value
105
- else
106
- @silence_warnings ? unknown_to_string(value) : unknown_to_string_with_warning(value)
107
- end
95
+ unknown_to_string_with_warning(value)
108
96
  end
109
97
  elsif value.instance_of?(Array)
110
98
  process(value) do
@@ -129,11 +117,7 @@ module Serialization
129
117
  { PCORE_TYPE_KEY => PCORE_TYPE_SENSITIVE, PCORE_VALUE_KEY => to_data(value.unwrap) }
130
118
  end
131
119
  else
132
- if @rich_data
133
- value_to_data_hash(value)
134
- else
135
- @silence_warnings ? unknown_to_string(value) : unknown_to_string_with_warning(value)
136
- end
120
+ unknown_to_data(value)
137
121
  end
138
122
  end
139
123
 
@@ -207,6 +191,10 @@ module Serialization
207
191
  v
208
192
  end
209
193
 
194
+ def unknown_to_data(value)
195
+ @rich_data ? value_to_data_hash(value) : unknown_to_string_with_warning(value)
196
+ end
197
+
210
198
  def unknown_key_to_string_with_warning(value)
211
199
  str = unknown_to_string(value)
212
200
  serialization_issue(Issues::SERIALIZATION_UNKNOWN_KEY_CONVERTED_TO_STRING, :path => path_to_s, :klass => value.class, :value => str)
@@ -614,20 +614,25 @@ class Checker4_0 < Evaluator::LiteralEvaluator
614
614
  string_path == manifest_setting || string_path.start_with?(manifest_setting)
615
615
  end
616
616
 
617
+ # Get the path of +file_path+ relative to the first directory in
618
+ # +modulepath_directories+ that is an ancestor of +file_path+. Return NO_PATH
619
+ # if none is found.
617
620
  def get_module_relative_path(file_path, modulepath_directories)
618
- clean_file = file_path.cleanpath
621
+ clean_file = file_path.cleanpath.to_s
619
622
  parent_path = modulepath_directories.find { |path_dir| is_parent_dir_of(path_dir, clean_file) }
620
623
  return NO_PATH if parent_path.nil?
621
624
 
622
625
  file_path.relative_path_from(Pathname.new(parent_path))
623
626
  end
627
+ private :get_module_relative_path
624
628
 
625
629
  def is_parent_dir_of(parent_dir, child_dir)
626
630
  parent_dir_path = Pathname.new(parent_dir)
627
631
  clean_parent = parent_dir_path.cleanpath.to_s + File::SEPARATOR
628
632
 
629
- return child_dir.to_s.start_with?(clean_parent)
633
+ return child_dir.start_with?(clean_parent)
630
634
  end
635
+ private :is_parent_dir_of
631
636
 
632
637
  def dir_to_names(relative_path)
633
638
  # Downcasing here because check is case-insensitive
@@ -84,7 +84,7 @@ Puppet::Type.type(:service).provide :init, :parent => :base do
84
84
  defpath = [defpath] unless defpath.is_a? Array
85
85
  instances = []
86
86
  defpath.each do |path|
87
- unless FileTest.directory?(path)
87
+ unless Puppet::FileSystem.directory?(path)
88
88
  Puppet.debug "Service path #{path} does not exist"
89
89
  next
90
90
  end
@@ -97,8 +97,9 @@ Puppet::Type.type(:service).provide :init, :parent => :base do
97
97
  fullpath = File.join(path, name)
98
98
  next if name =~ /^\./
99
99
  next if exclude.include? name
100
- next if not FileTest.executable?(fullpath)
101
- next if not is_init?(fullpath)
100
+ next if Puppet::FileSystem.directory?(fullpath)
101
+ next unless Puppet::FileSystem.executable?(fullpath)
102
+ next unless is_init?(fullpath)
102
103
  instances << new(:name => name, :path => path, :hasstatus => true)
103
104
  end
104
105
  end
@@ -122,7 +123,7 @@ Puppet::Type.type(:service).provide :init, :parent => :base do
122
123
 
123
124
  def paths
124
125
  @paths ||= @resource[:path].find_all do |path|
125
- if File.directory?(path)
126
+ if Puppet::FileSystem.directory?(path)
126
127
  true
127
128
  else
128
129
  if Puppet::FileSystem.exist?(path)
@@ -24,6 +24,7 @@ class Puppet::Resource::TypeCollection
24
24
  @definitions = {}
25
25
  @nodes = {}
26
26
  @notfound = {}
27
+ # always lock the environment before acquiring this lock
27
28
  @lock = Puppet::Concurrent::Lock.new
28
29
 
29
30
  # So we can keep a list and match the first-defined regex
@@ -185,26 +186,29 @@ class Puppet::Resource::TypeCollection
185
186
  # Resolve namespaces and find the given object. Autoload it if
186
187
  # necessary.
187
188
  def find_or_load(name, type)
188
- @lock.synchronize do
189
- # Name is always absolute, but may start with :: which must be removed
190
- fqname = (name[0,2] == COLON_COLON ? name[2..-1] : name)
191
-
192
- result = send(type, fqname)
193
- unless result
194
- if @notfound[ fqname ] && Puppet[ :ignoremissingtypes ]
195
- # do not try to autoload if we already tried and it wasn't conclusive
196
- # as this is a time consuming operation. Warn the user.
197
- # Check first if debugging is on since the call to debug_once is expensive
198
- if Puppet[:debug]
199
- debug_once _("Not attempting to load %{type} %{fqname} as this object was missing during a prior compilation") % { type: type, fqname: fqname }
189
+ # always lock the environment before locking the type collection
190
+ @environment.lock.synchronize do
191
+ @lock.synchronize do
192
+ # Name is always absolute, but may start with :: which must be removed
193
+ fqname = (name[0,2] == COLON_COLON ? name[2..-1] : name)
194
+
195
+ result = send(type, fqname)
196
+ unless result
197
+ if @notfound[ fqname ] && Puppet[ :ignoremissingtypes ]
198
+ # do not try to autoload if we already tried and it wasn't conclusive
199
+ # as this is a time consuming operation. Warn the user.
200
+ # Check first if debugging is on since the call to debug_once is expensive
201
+ if Puppet[:debug]
202
+ debug_once _("Not attempting to load %{type} %{fqname} as this object was missing during a prior compilation") % { type: type, fqname: fqname }
203
+ end
204
+ else
205
+ fqname = munge_name(fqname)
206
+ result = loader.try_load_fqname(type, fqname)
207
+ @notfound[ fqname ] = result.nil?
200
208
  end
201
- else
202
- fqname = munge_name(fqname)
203
- result = loader.try_load_fqname(type, fqname)
204
- @notfound[ fqname ] = result.nil?
205
209
  end
210
+ result
206
211
  end
207
- result
208
212
  end
209
213
  end
210
214
 
@@ -117,7 +117,9 @@ class Puppet::SSL::Verifier
117
117
  return false
118
118
  end
119
119
 
120
- when OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH # new in ruby-openssl 2.2.0/ruby 3.0
120
+ # ruby-openssl#74ef8c0cc56b840b772240f2ee2b0fc0aafa2743 now sets the
121
+ # store_context error when the cert is mismatched
122
+ when OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH
121
123
  @last_error = Puppet::SSL::CertMismatchError.new(peer_cert, @hostname)
122
124
  return false
123
125
 
@@ -6,6 +6,26 @@ require_relative '../../puppet/util/yaml'
6
6
  # as calculating corrective_change).
7
7
  # @api private
8
8
  class Puppet::Transaction::Persistence
9
+
10
+ def self.allowed_classes
11
+ @allowed_classes ||= [
12
+ Symbol,
13
+ Time,
14
+ Regexp,
15
+ # URI is excluded, because it serializes all instance variables including the
16
+ # URI parser. Better to serialize the URL encoded representation.
17
+ SemanticPuppet::Version,
18
+ # SemanticPuppet::VersionRange has many nested classes and is unlikely to be
19
+ # used directly, so ignore it
20
+ Puppet::Pops::Time::Timestamp,
21
+ Puppet::Pops::Time::TimeData,
22
+ Puppet::Pops::Time::Timespan,
23
+ Puppet::Pops::Types::PBinaryType::Binary,
24
+ # Puppet::Pops::Types::PSensitiveType::Sensitive values are excluded from
25
+ # the persistence store, ignore it.
26
+ ].freeze
27
+ end
28
+
9
29
  def initialize
10
30
  @old_data = {}
11
31
  @new_data = {"resources" => {}}
@@ -62,7 +82,7 @@ class Puppet::Transaction::Persistence
62
82
  result = nil
63
83
  Puppet::Util.benchmark(:debug, _("Loaded transaction store file in %{seconds} seconds")) do
64
84
  begin
65
- result = Puppet::Util::Yaml.safe_load_file(filename, [Symbol, Time])
85
+ result = Puppet::Util::Yaml.safe_load_file(filename, self.class.allowed_classes)
66
86
  rescue Puppet::Util::Yaml::YamlLoadError => detail
67
87
  Puppet.log_exception(detail, _("Transaction store file %{filename} is corrupt (%{detail}); replacing") % { filename: filename, detail: detail })
68
88
 
@@ -87,17 +107,7 @@ class Puppet::Transaction::Persistence
87
107
 
88
108
  # Save data from internal class to persistence store on disk.
89
109
  def save
90
- converted_data = Puppet::Pops::Serialization::ToDataConverter.convert(
91
- @new_data, {
92
- symbol_as_string: false,
93
- local_reference: false,
94
- type_by_reference: true,
95
- force_symbol: true,
96
- silence_warnings: true,
97
- message_prefix: to_s
98
- }
99
- )
100
- Puppet::Util::Yaml.dump(converted_data, Puppet[:transactionstorefile])
110
+ Puppet::Util::Yaml.dump(@new_data, Puppet[:transactionstorefile])
101
111
  end
102
112
 
103
113
  # Use the catalog and run_mode to determine if persistence should be enabled or not
@@ -457,7 +457,7 @@ module Puppet
457
457
 
458
458
  exec { '/bin/echo root >> /usr/lib/cron/cron.allow':
459
459
  path => '/usr/bin:/usr/sbin:/bin',
460
- unless => 'grep root /usr/lib/cron/cron.allow 2>/dev/null',
460
+ unless => 'grep ^root$ /usr/lib/cron/cron.allow 2>/dev/null',
461
461
  }
462
462
 
463
463
  This would add `root` to the cron.allow file (on Solaris) unless
@@ -79,7 +79,7 @@ module Puppet
79
79
  return :absent unless stat
80
80
  ftype = stat.ftype
81
81
  # Don't even try to manage the content on directories or links
82
- return nil if ["directory","link"].include?(ftype)
82
+ return nil if ['directory', 'link', 'fifo', 'socket'].include?(ftype)
83
83
 
84
84
  begin
85
85
  resource.parameter(:checksum).sum_file(resource[:path])
@@ -23,7 +23,14 @@ module Puppet
23
23
  # evaluate this property, because they might be added during the catalog
24
24
  # apply.
25
25
  @should.map! do |val|
26
- provider.name2gid(val) or raise "Could not find group #{val}"
26
+ gid = provider.name2gid(val)
27
+ if gid
28
+ gid
29
+ elsif provider.resource.noop?
30
+ return false
31
+ else
32
+ raise "Could not find group #{val}"
33
+ end
27
34
  end
28
35
 
29
36
  @should.include?(current)
@@ -18,7 +18,14 @@ module Puppet
18
18
  # evaluate this property, because they might be added during the catalog
19
19
  # apply.
20
20
  @should.map! do |val|
21
- provider.name2uid(val) or raise "Could not find user #{val}"
21
+ uid = provider.name2uid(val)
22
+ if uid
23
+ uid
24
+ elsif provider.resource.noop?
25
+ return false
26
+ else
27
+ raise "Could not find user #{val}"
28
+ end
22
29
  end
23
30
 
24
31
  return true if @should.include?(current)
@@ -66,7 +66,6 @@ module Puppet
66
66
  newproperty(:ensure, :parent => Puppet::Property::Ensure) do
67
67
  newvalue(:present, :event => :user_created) do
68
68
  provider.create
69
- @resource.generate
70
69
  end
71
70
 
72
71
  newvalue(:absent, :event => :user_removed) do
@@ -694,8 +693,7 @@ module Puppet
694
693
  end
695
694
 
696
695
  def generate
697
- if !self[:purge_ssh_keys].empty? && self[:purge_ssh_keys] != :false
698
- return [] if self[:ensure] == :present && !provider.exists?
696
+ if !self[:purge_ssh_keys].empty?
699
697
  if Puppet::Type.type(:ssh_authorized_key).nil?
700
698
  warning _("Ssh_authorized_key type is not available. Cannot purge SSH keys.")
701
699
  else
@@ -744,6 +742,45 @@ module Puppet
744
742
  end
745
743
  raise ArgumentError, _("purge_ssh_keys must be true, false, or an array of file names, not %{value}") % { value: value.inspect }
746
744
  end
745
+
746
+ munge do |value|
747
+ # Resolve string, boolean and symbol forms of true and false to a
748
+ # single representation.
749
+ case value
750
+ when :false, false, "false"
751
+ []
752
+ when :true, true, "true"
753
+ home = homedir
754
+ home ? [ "#{home}/.ssh/authorized_keys" ] : []
755
+ else
756
+ # value can be a string or array - munge each value
757
+ [ value ].flatten.map do |entry|
758
+ authorized_keys_path(entry)
759
+ end.compact
760
+ end
761
+ end
762
+
763
+ private
764
+
765
+ def homedir
766
+ resource[:home] || Dir.home(resource[:name])
767
+ rescue ArgumentError
768
+ Puppet.debug("User '#{resource[:name]}' does not exist")
769
+ nil
770
+ end
771
+
772
+ def authorized_keys_path(entry)
773
+ return entry unless entry.match?(%r{^(?:~|%h)/})
774
+
775
+ # if user doesn't exist (yet), ignore nonexistent homedir
776
+ home = homedir
777
+ return nil unless home
778
+
779
+ # compiler freezes "value" so duplicate using a gsub, second mutating gsub! is then ok
780
+ entry = entry.gsub(%r{^~/}, "#{home}/")
781
+ entry.gsub!(%r{^%h/}, "#{home}/")
782
+ entry
783
+ end
747
784
  end
748
785
 
749
786
  newproperty(:loginclass, :required_features => :manages_loginclass) do
@@ -765,7 +802,7 @@ module Puppet
765
802
  # @see generate
766
803
  # @api private
767
804
  def find_unmanaged_keys
768
- munged_unmanaged_keys.
805
+ self[:purge_ssh_keys].
769
806
  select { |f| File.readable?(f) }.
770
807
  map { |f| unknown_keys_in_file(f) }.
771
808
  flatten.each do |res|
@@ -777,41 +814,6 @@ module Puppet
777
814
  end
778
815
  end
779
816
 
780
- def munged_unmanaged_keys
781
- value = self[:purge_ssh_keys]
782
-
783
- # Resolve string, boolean and symbol forms of true and false to a
784
- # single representation.
785
- test_sym = value.to_s.intern
786
- value = test_sym if [:true, :false].include? test_sym
787
-
788
- return [] if value == :false
789
-
790
- home = self[:home]
791
- begin
792
- home ||= provider.home
793
- rescue
794
- Puppet.debug("User '#{self[:name]}' does not exist")
795
- end
796
-
797
- if home.to_s.empty? || !Dir.exist?(home.to_s)
798
- if value == :true || [ value ].flatten.any? { |v| v.start_with?('~/', '%h/') }
799
- Puppet.debug("User '#{self[:name]}' has no home directory set to purge ssh keys from.")
800
- return []
801
- end
802
- end
803
-
804
- return [ "#{home}/.ssh/authorized_keys" ] if value == :true
805
-
806
- # value is an array - munge each value
807
- [ value ].flatten.map do |entry|
808
- # make sure frozen value is duplicated by using a gsub, second mutating gsub! is then ok
809
- entry = entry.gsub(/^~\//, "#{home}/")
810
- entry.gsub!(/^%h\//, "#{home}/")
811
- entry
812
- end
813
- end
814
-
815
817
  # Parse an ssh authorized keys file superficially, extract the comments
816
818
  # on the keys. These are considered names of possible ssh_authorized_keys
817
819
  # resources. Keys that are managed by the present catalog are ignored.
@@ -26,6 +26,23 @@ module Puppet::Util
26
26
  require 'json'
27
27
  end
28
28
 
29
+ # Load the content from a file as JSON if
30
+ # contents are in valid format. This method does not
31
+ # raise error but returns `nil` when invalid file is
32
+ # given.
33
+ def self.load_file_if_valid(filename, options = {})
34
+ load_file(filename, options)
35
+ rescue Puppet::Util::Json::ParseError, ArgumentError, Errno::ENOENT => detail
36
+ Puppet.debug("Could not retrieve JSON content from '#{filename}': #{detail.message}")
37
+ nil
38
+ end
39
+
40
+ # Load the content from a file as JSON.
41
+ def self.load_file(filename, options = {})
42
+ json = Puppet::FileSystem.read(filename, :encoding => 'utf-8')
43
+ load(json, options)
44
+ end
45
+
29
46
  # These methods do similar processing to the fallback implemented by MultiJson
30
47
  # when using the built-in JSON backend, to ensure consistent behavior
31
48
  # whether or not MultiJson can be loaded.
@@ -105,9 +105,14 @@ class Puppet::Util::Log
105
105
  def Log.level=(level)
106
106
  level = level.intern unless level.is_a?(Symbol)
107
107
 
108
- raise Puppet::DevError, _("Invalid loglevel %{level}") % { level: level } unless @levels.include?(level)
108
+ # loglevel is a 0-based index
109
+ loglevel = @levels.index(level)
110
+ raise Puppet::DevError, _("Invalid loglevel %{level}") % { level: level } unless loglevel
109
111
 
110
- @loglevel = @levels.index(level)
112
+ return if @loglevel == loglevel
113
+
114
+ # loglevel changed
115
+ @loglevel = loglevel
111
116
 
112
117
  # Enable or disable Facter debugging
113
118
  Puppet.runtime[:facter].debugging(level == :debug)
@@ -29,6 +29,28 @@ class Object
29
29
  end
30
30
  end
31
31
 
32
+ if RUBY_VERSION.to_f < 3.0
33
+ # absolute/relative were optimized to avoid chop_basename in ruby 3
34
+ # see https://github.com/ruby/ruby/commit/39312cf4d6c2ab3f07d688ad1a467c8f84b58db0
35
+ require 'pathname'
36
+ class Pathname
37
+ if File.dirname('A:') == 'A:.' # DOSish drive letter
38
+ ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/o
39
+ else
40
+ ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/o
41
+ end
42
+ private_constant :ABSOLUTE_PATH
43
+
44
+ def absolute?
45
+ ABSOLUTE_PATH.match? @path
46
+ end
47
+
48
+ def relative?
49
+ !absolute?
50
+ end
51
+ end
52
+ end
53
+
32
54
  # (#19151) Reject all SSLv2 ciphers and handshakes
33
55
  require_relative '../../puppet/ssl/openssl_loader'
34
56
  unless Puppet::Util::Platform.jruby_fips?
@@ -57,8 +79,6 @@ unless Puppet::Util::Platform.jruby_fips?
57
79
  end
58
80
 
59
81
  if Puppet::Util::Platform.windows?
60
- require_relative '../../puppet/util/windows'
61
-
62
82
  class OpenSSL::X509::Store
63
83
  @puppet_certs_loaded = false
64
84
  alias __original_set_default_paths set_default_paths
@@ -83,8 +103,10 @@ if Puppet::Util::Platform.windows?
83
103
  end
84
104
 
85
105
  unless Puppet::Util::Platform.jruby_fips?
86
- unless OpenSSL::X509.const_defined?(:V_ERR_HOSTNAME_MISMATCH)
87
- OpenSSL::X509.const_set(:V_ERR_HOSTNAME_MISMATCH, 62)
106
+ unless defined?(OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH)
107
+ module OpenSSL::X509
108
+ OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH = 0x3E
109
+ end
88
110
  end
89
111
 
90
112
  # jruby-openssl doesn't support this
@@ -1,6 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  module Puppet::Util::Package
2
- def versioncmp(version_a, version_b)
3
+ def versioncmp(version_a, version_b, ignore_trailing_zeroes = false)
3
4
  vre = /[-.]|\d+|[^-.\d]+/
5
+
6
+ if ignore_trailing_zeroes
7
+ version_a = normalize(version_a)
8
+ version_b = normalize(version_b)
9
+ end
10
+
4
11
  ax = version_a.scan(vre)
5
12
  bx = version_b.scan(vre)
6
13
 
@@ -8,24 +15,26 @@ module Puppet::Util::Package
8
15
  a = ax.shift
9
16
  b = bx.shift
10
17
 
11
- if( a == b ) then next
12
- elsif (a == '-' && b == '-') then next
13
- elsif (a == '-') then return -1
14
- elsif (b == '-') then return 1
15
- elsif (a == '.' && b == '.') then next
16
- elsif (a == '.' ) then return -1
17
- elsif (b == '.' ) then return 1
18
- elsif (a =~ /^\d+$/ && b =~ /^\d+$/) then
19
- if( a =~ /^0/ or b =~ /^0/ ) then
20
- return a.to_s.upcase <=> b.to_s.upcase
21
- end
18
+ next if a == b
19
+ return -1 if a == '-'
20
+ return 1 if b == '-'
21
+ return -1 if a == '.'
22
+ return 1 if b == '.'
23
+ if a =~ /^\d+$/ && b =~ /^\d+$/
24
+ return a.to_s.upcase <=> b.to_s.upcase if a =~ /^0/ || b =~ /^0/
22
25
  return a.to_i <=> b.to_i
23
- else
24
- return a.upcase <=> b.upcase
25
26
  end
27
+ return a.upcase <=> b.upcase
26
28
  end
27
- version_a <=> version_b;
29
+ version_a <=> version_b
28
30
  end
29
-
30
31
  module_function :versioncmp
32
+
33
+ def self.normalize(version)
34
+ version = version.split('-')
35
+ version.first.sub!(/([\.0]+)$/, '')
36
+
37
+ version.join('-')
38
+ end
39
+ private_class_method :normalize
31
40
  end
@@ -24,7 +24,11 @@ module Puppet::Util::Yaml
24
24
  # @raise [YamlLoadException] If deserialization fails.
25
25
  # @return The parsed YAML, which can be Hash, Array or scalar types.
26
26
  def self.safe_load(yaml, allowed_classes = [], filename = nil)
27
- data = YAML.safe_load(yaml, allowed_classes, [], true, filename)
27
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0')
28
+ data = YAML.safe_load(yaml, permitted_classes: allowed_classes, aliases: true, filename: filename)
29
+ else
30
+ data = YAML.safe_load(yaml, allowed_classes, [], true, filename)
31
+ end
28
32
  data = false if data.nil?
29
33
  data
30
34
  rescue ::Psych::DisallowedClass => detail
@@ -42,6 +46,17 @@ module Puppet::Util::Yaml
42
46
  safe_load(yaml, allowed_classes, filename)
43
47
  end
44
48
 
49
+ # Safely load the content from a file as YAML if
50
+ # contents are in valid format. This method does not
51
+ # raise error but returns `nil` when invalid file is
52
+ # given.
53
+ def self.safe_load_file_if_valid(filename, allowed_classes = [])
54
+ safe_load_file(filename, allowed_classes)
55
+ rescue YamlLoadError, ArgumentError, Errno::ENOENT => detail
56
+ Puppet.debug("Could not retrieve YAML content from '#{filename}': #{detail.message}")
57
+ nil
58
+ end
59
+
45
60
  def self.dump(structure, filename)
46
61
  Puppet::FileSystem.replace_file(filename, 0660) do |fh|
47
62
  YAML.dump(structure, fh)
data/lib/puppet/util.rb CHANGED
@@ -7,6 +7,7 @@ require 'uri'
7
7
  require 'pathname'
8
8
  require 'ostruct'
9
9
  require_relative 'util/platform'
10
+ require_relative 'util/windows'
10
11
  require_relative 'util/symbolic_file_mode'
11
12
  require_relative '../puppet/file_system/uniquefile'
12
13
  require 'securerandom'
@@ -6,7 +6,7 @@
6
6
  # Raketasks and such to set the version based on the output of `git describe`
7
7
 
8
8
  module Puppet
9
- PUPPETVERSION = '7.12.1'
9
+ PUPPETVERSION = '7.15.0'
10
10
 
11
11
  ##
12
12
  # version is a public API method intended to always provide a fast and
data/lib/puppet.rb CHANGED
@@ -355,3 +355,4 @@ require_relative 'puppet/util/storage'
355
355
  require_relative 'puppet/file_bucket/file'
356
356
  require_relative 'puppet/plugins/configuration'
357
357
  require_relative 'puppet/pal/pal_api'
358
+ require_relative 'puppet/node/facts'