puppet 7.11.0-universal-darwin → 7.14.0-universal-darwin

Sign up to get free protection for your applications and to get access to all the features.
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