puppet 7.11.0-x64-mingw32 → 7.14.0-x64-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +1 -1
  3. data/Gemfile +2 -2
  4. data/Gemfile.lock +24 -19
  5. data/ext/project_data.yaml +1 -1
  6. data/lib/puppet/application/lookup.rb +78 -24
  7. data/lib/puppet/concurrent/thread_local_singleton.rb +5 -3
  8. data/lib/puppet/configurer.rb +74 -25
  9. data/lib/puppet/defaults.rb +20 -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 +3 -2
  18. data/lib/puppet/functions/versioncmp.rb +6 -2
  19. data/lib/puppet/generate/type.rb +9 -0
  20. data/lib/puppet/graph/simple_graph.rb +2 -1
  21. data/lib/puppet/http/client.rb +1 -1
  22. data/lib/puppet/http/redirector.rb +5 -0
  23. data/lib/puppet/node.rb +1 -1
  24. data/lib/puppet/parser/resource.rb +1 -1
  25. data/lib/puppet/pops/evaluator/closure.rb +7 -5
  26. data/lib/puppet/pops/evaluator/runtime3_resource_support.rb +1 -0
  27. data/lib/puppet/pops/parser/code_merger.rb +4 -4
  28. data/lib/puppet/pops/parser/egrammar.ra +2 -0
  29. data/lib/puppet/pops/parser/eparser.rb +574 -558
  30. data/lib/puppet/pops/serialization/to_data_converter.rb +6 -18
  31. data/lib/puppet/pops/validation/checker4_0.rb +7 -2
  32. data/lib/puppet/provider/package/pkg.rb +10 -0
  33. data/lib/puppet/provider/service/init.rb +5 -4
  34. data/lib/puppet/provider/user/useradd.rb +20 -0
  35. data/lib/puppet/resource/catalog.rb +1 -1
  36. data/lib/puppet/resource/type_collection.rb +21 -17
  37. data/lib/puppet/resource.rb +38 -5
  38. data/lib/puppet/ssl/verifier.rb +3 -1
  39. data/lib/puppet/transaction/persistence.rb +22 -12
  40. data/lib/puppet/type/file/data_sync.rb +1 -1
  41. data/lib/puppet/type/file/group.rb +8 -1
  42. data/lib/puppet/type/file/owner.rb +8 -1
  43. data/lib/puppet/type/service.rb +8 -3
  44. data/lib/puppet/type/user.rb +41 -39
  45. data/lib/puppet/util/autoload.rb +1 -1
  46. data/lib/puppet/util/json.rb +20 -0
  47. data/lib/puppet/util/log.rb +7 -2
  48. data/lib/puppet/util/monkey_patches.rb +26 -2
  49. data/lib/puppet/util/package.rb +25 -16
  50. data/lib/puppet/util/windows/service.rb +0 -5
  51. data/lib/puppet/util/windows.rb +3 -0
  52. data/lib/puppet/util/yaml.rb +16 -1
  53. data/lib/puppet/version.rb +1 -1
  54. data/lib/puppet.rb +1 -0
  55. data/locales/puppet.pot +5 -9737
  56. data/man/man5/puppet.conf.5 +21 -2
  57. data/man/man8/puppet-agent.8 +1 -1
  58. data/man/man8/puppet-apply.8 +1 -1
  59. data/man/man8/puppet-catalog.8 +1 -1
  60. data/man/man8/puppet-config.8 +1 -1
  61. data/man/man8/puppet-describe.8 +1 -1
  62. data/man/man8/puppet-device.8 +1 -1
  63. data/man/man8/puppet-doc.8 +1 -1
  64. data/man/man8/puppet-epp.8 +1 -1
  65. data/man/man8/puppet-facts.8 +1 -1
  66. data/man/man8/puppet-filebucket.8 +1 -1
  67. data/man/man8/puppet-generate.8 +1 -1
  68. data/man/man8/puppet-help.8 +1 -1
  69. data/man/man8/puppet-lookup.8 +9 -6
  70. data/man/man8/puppet-module.8 +1 -1
  71. data/man/man8/puppet-node.8 +1 -1
  72. data/man/man8/puppet-parser.8 +1 -1
  73. data/man/man8/puppet-plugin.8 +1 -1
  74. data/man/man8/puppet-report.8 +1 -1
  75. data/man/man8/puppet-resource.8 +1 -1
  76. data/man/man8/puppet-script.8 +1 -1
  77. data/man/man8/puppet-ssl.8 +1 -1
  78. data/man/man8/puppet.8 +2 -2
  79. data/spec/fixtures/integration/application/agent/cached_deferred_catalog.json +2 -1
  80. data/spec/fixtures/unit/forge/bacula.json +1 -1
  81. data/spec/integration/application/agent_spec.rb +28 -0
  82. data/spec/integration/application/lookup_spec.rb +32 -6
  83. data/spec/integration/parser/pcore_resource_spec.rb +20 -0
  84. data/spec/shared_contexts/l10n.rb +5 -0
  85. data/spec/unit/application/lookup_spec.rb +131 -10
  86. data/spec/unit/concurrent/thread_local_singleton_spec.rb +39 -0
  87. data/spec/unit/configurer_spec.rb +167 -60
  88. data/spec/unit/face/generate_spec.rb +64 -0
  89. data/spec/unit/file_system/uniquefile_spec.rb +7 -1
  90. data/spec/unit/file_system_spec.rb +34 -4
  91. data/spec/unit/forge/module_release_spec.rb +3 -3
  92. data/spec/unit/functions/versioncmp_spec.rb +40 -4
  93. data/spec/unit/http/client_spec.rb +58 -1
  94. data/spec/unit/network/formats_spec.rb +6 -0
  95. data/spec/unit/node_spec.rb +6 -0
  96. data/spec/unit/pops/parser/parse_containers_spec.rb +2 -2
  97. data/spec/unit/pops/serialization/to_from_hr_spec.rb +0 -58
  98. data/spec/unit/pops/validator/validator_spec.rb +5 -0
  99. data/spec/unit/provider/package/pkg_spec.rb +15 -0
  100. data/spec/unit/provider/service/gentoo_spec.rb +6 -5
  101. data/spec/unit/provider/service/init_spec.rb +15 -9
  102. data/spec/unit/provider/service/openwrt_spec.rb +21 -29
  103. data/spec/unit/provider/service/redhat_spec.rb +3 -2
  104. data/spec/unit/provider/user/useradd_spec.rb +40 -0
  105. data/spec/unit/resource/catalog_spec.rb +14 -1
  106. data/spec/unit/resource_spec.rb +58 -2
  107. data/spec/unit/transaction/persistence_spec.rb +51 -0
  108. data/spec/unit/type/file/group_spec.rb +7 -0
  109. data/spec/unit/type/file/owner_spec.rb +7 -0
  110. data/spec/unit/type/service_spec.rb +27 -0
  111. data/spec/unit/type/user_spec.rb +67 -45
  112. data/spec/unit/util/autoload_spec.rb +25 -8
  113. data/spec/unit/util/json_spec.rb +126 -0
  114. data/spec/unit/util/yaml_spec.rb +37 -13
  115. metadata +15 -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
@@ -237,7 +237,17 @@ Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package d
237
237
  end
238
238
  self.unhold if self.properties[:mark] == :hold
239
239
  begin
240
+ tries = 1
241
+ # pkg install exits with code 7 when the image is currently in use by another process and cannot be modified
240
242
  r = exec_cmd(command(:pkg), command, *args, name)
243
+ while r[:exit] == 7 do
244
+ if tries > 4
245
+ raise Puppet::Error, _("Pkg could not install %{name} after %{tries} tries. Aborting run") % { name: name, tries: tries }
246
+ end
247
+ sleep 2 ** tries
248
+ tries += 1
249
+ r = exec_cmd(command(:pkg), command, *args, name)
250
+ end
241
251
  ensure
242
252
  self.hold if @resource[:mark] == :hold
243
253
  end
@@ -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)
@@ -72,6 +72,16 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
72
72
  get(:comment)
73
73
  end
74
74
 
75
+ def shell
76
+ return localshell if @resource.forcelocal?
77
+ get(:shell)
78
+ end
79
+
80
+ def home
81
+ return localhome if @resource.forcelocal?
82
+ get(:home)
83
+ end
84
+
75
85
  def groups
76
86
  return localgroups if @resource.forcelocal?
77
87
  super
@@ -123,6 +133,16 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
123
133
  user[:gecos]
124
134
  end
125
135
 
136
+ def localshell
137
+ user = finduser(:account, resource[:name])
138
+ user[:shell]
139
+ end
140
+
141
+ def localhome
142
+ user = finduser(:account, resource[:name])
143
+ user[:directory]
144
+ end
145
+
126
146
  def localgroups
127
147
  @groups_of ||= {}
128
148
  group_file = '/etc/group'
@@ -313,7 +313,7 @@ class Puppet::Resource::Catalog < Puppet::Graph::SimpleGraph
313
313
  super()
314
314
  @name = name
315
315
  @catalog_uuid = SecureRandom.uuid
316
- @catalog_format = 1
316
+ @catalog_format = 2
317
317
  @metadata = {}
318
318
  @recursive_metadata = {}
319
319
  @classes = []
@@ -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
 
@@ -11,7 +11,7 @@ class Puppet::Resource
11
11
  include Puppet::Util::PsychSupport
12
12
 
13
13
  include Enumerable
14
- attr_accessor :file, :line, :catalog, :exported, :virtual, :strict
14
+ attr_accessor :file, :line, :catalog, :exported, :virtual, :strict, :kind
15
15
  attr_reader :type, :title, :parameters
16
16
 
17
17
  # @!attribute [rw] sensitive_parameters
@@ -29,10 +29,15 @@ class Puppet::Resource
29
29
  EMPTY_ARRAY = [].freeze
30
30
  EMPTY_HASH = {}.freeze
31
31
 
32
- ATTRIBUTES = [:file, :line, :exported].freeze
32
+ ATTRIBUTES = [:file, :line, :exported, :kind].freeze
33
33
  TYPE_CLASS = 'Class'.freeze
34
34
  TYPE_NODE = 'Node'.freeze
35
35
 
36
+ CLASS_STRING = 'class'.freeze
37
+ DEFINED_TYPE_STRING = 'defined_type'.freeze
38
+ COMPILABLE_TYPE_STRING = 'compilable_type'.freeze
39
+ UNKNOWN_TYPE_STRING = 'unknown'.freeze
40
+
36
41
  PCORE_TYPE_KEY = '__ptype'.freeze
37
42
  VALUE_KEY = 'value'.freeze
38
43
 
@@ -193,6 +198,18 @@ class Puppet::Resource
193
198
  resource_type.is_a?(Puppet::CompilableResourceType)
194
199
  end
195
200
 
201
+ def self.to_kind(resource_type)
202
+ if resource_type == CLASS_STRING
203
+ CLASS_STRING
204
+ elsif resource_type.is_a?(Puppet::Resource::Type) && resource_type.type == :definition
205
+ DEFINED_TYPE_STRING
206
+ elsif resource_type.is_a?(Puppet::CompilableResourceType)
207
+ COMPILABLE_TYPE_STRING
208
+ else
209
+ UNKNOWN_TYPE_STRING
210
+ end
211
+ end
212
+
196
213
  # Iterate over each param/value pair, as required for Enumerable.
197
214
  def each
198
215
  parameters.each { |p,v| yield p, v }
@@ -247,6 +264,7 @@ class Puppet::Resource
247
264
  src = type
248
265
  self.file = src.file
249
266
  self.line = src.line
267
+ self.kind = src.kind
250
268
  self.exported = src.exported
251
269
  self.virtual = src.virtual
252
270
  self.set_tags(src)
@@ -309,6 +327,7 @@ class Puppet::Resource
309
327
 
310
328
  rt = resource_type
311
329
 
330
+ self.kind = self.class.to_kind(rt) unless kind
312
331
  if strict? && rt.nil?
313
332
  if self.class?
314
333
  raise ArgumentError, _("Could not find declared class %{title}") % { title: title }
@@ -468,10 +487,24 @@ class Puppet::Resource
468
487
  ref
469
488
  end
470
489
 
471
- # Convert our resource to a RAL resource instance. Creates component
472
- # instances for resource types that don't exist.
490
+ # Convert our resource to a RAL resource instance. Creates component
491
+ # instances for resource types that are not of a compilable_type kind. In case
492
+ # the resource doesn’t exist and it’s compilable_type kind, raise an error.
493
+ # There are certain cases where a resource won't be in a catalog, such as
494
+ # when we create a resource directly by using Puppet::Resource.new(...), so we
495
+ # must check its kind before deciding whether the catalog format is of an older
496
+ # version or not.
473
497
  def to_ral
474
- typeklass = Puppet::Type.type(self.type) || Puppet::Type.type(:component)
498
+ if self.kind == COMPILABLE_TYPE_STRING
499
+ typeklass = Puppet::Type.type(self.type)
500
+ elsif self.catalog && self.catalog.catalog_format >= 2
501
+ typeklass = Puppet::Type.type(:component)
502
+ else
503
+ typeklass = Puppet::Type.type(self.type) || Puppet::Type.type(:component)
504
+ end
505
+
506
+ raise(Puppet::Error, "Resource type '#{self.type}' was not found") unless typeklass
507
+
475
508
  typeklass.new(self)
476
509
  end
477
510
 
@@ -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
@@ -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)
@@ -272,9 +272,14 @@ module Puppet
272
272
 
273
273
  newparam(:timeout, :required_features => :configurable_timeout) do
274
274
  desc "Specify an optional minimum timeout (in seconds) for puppet to wait when syncing service properties"
275
- defaultto { provider.class.respond_to?(:default_timeout) ? provider.default_timeout : 10 }
276
- validate do |value|
277
- if (not value.is_a? Integer) || value < 1
275
+ defaultto { provider.respond_to?(:default_timeout) ? provider.default_timeout : 10 }
276
+
277
+ munge do |value|
278
+ begin
279
+ value = value.to_i
280
+ raise if value < 1
281
+ value
282
+ rescue
278
283
  raise Puppet::Error.new(_("\"%{value}\" is not a positive integer: the timeout parameter must be specified as a positive integer") % { value: value })
279
284
  end
280
285
  end
@@ -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.
@@ -117,7 +117,7 @@ class Puppet::Util::Autoload
117
117
 
118
118
  # @api private
119
119
  def files_in_dir(dir, path)
120
- dir = Pathname.new(File.expand_path(dir))
120
+ dir = Pathname.new(Puppet::FileSystem.expand_path(dir))
121
121
  Dir.glob(File.join(dir, path, "*.rb")).collect do |file|
122
122
  Pathname.new(file).relative_path_from(dir).to_s
123
123
  end
@@ -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.
@@ -60,6 +77,9 @@ module Puppet::Util
60
77
  def self.dump(object, options = {})
61
78
  if defined? MultiJson
62
79
  MultiJson.dump(object, options)
80
+ elsif options.is_a?(JSON::State)
81
+ # we're being called recursively
82
+ object.to_json(options)
63
83
  else
64
84
  options.merge!(::JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
65
85
  object.to_json(options)
@@ -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?
@@ -83,8 +105,10 @@ if Puppet::Util::Platform.windows?
83
105
  end
84
106
 
85
107
  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)
108
+ unless defined?(OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH)
109
+ module OpenSSL::X509
110
+ OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH = 0x3E
111
+ end
88
112
  end
89
113
 
90
114
  # jruby-openssl doesn't support this