chef 16.9.32 → 16.10.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 244ba97196d96199132e3085f6c351d495b2db06bcb8c66fbedf2f89c2ddf82a
4
- data.tar.gz: 944aec394ec8916f92fd7124d33dbf25a9c4dd40eb6dbdcbdd79b1269f07ecc0
3
+ metadata.gz: c34d608da9c455be75a96a34306d2f48c696791569efad3a74d949ffa057a1c6
4
+ data.tar.gz: 53948ca32fb71521ba9b9502f7bd3a3aa10754a6f1971b1c3756ea8caa682de9
5
5
  SHA512:
6
- metadata.gz: 830152b0c8f02a4dc2f1bc015d3e2062d20c8e30777d0bfb764cbe15d9b2005503aebab3a0a368b56d9f6f76dbc8abcea45398a554a0776da273c4f1e9266146
7
- data.tar.gz: 705c961f6472469ce603f94e8498de015db482fcb386659da1babef73afefe589eef4e2cb5c933796b15c0ee3e6ea7f5192481a663a281721e6d5a17a7ad3478
6
+ metadata.gz: 07d4cc0280c0619c9f9caf772d5f8f5c1edbe5e05cea905a5033c218dd6c0fdfd2c3159dfc18eafdc66c1dc0ed7da28839bade97514f910967b8adf1930b6707
7
+ data.tar.gz: 00a4ee34617c879ab9de9dba5ea9b5842c3fd1da604c7ac8c9e14ae7ce2f1575b5b0227d2ac947937519df90802192f6d49340890f57ec08c7df0adb7b6f0734
data/Gemfile CHANGED
@@ -53,7 +53,7 @@ end
53
53
 
54
54
  group(:development, :test) do
55
55
  gem "rake"
56
- gem "rspec", "=3.9.0" # remove pin once https://github.com/chef/chef/issues/10817 is resolved
56
+ gem "rspec"
57
57
  gem "webmock"
58
58
  gem "fauxhai-ng" # for chef-utils gem
59
59
  end
@@ -14,7 +14,7 @@ gemspec.add_dependency "win32-service", ">= 2.1.5", "< 3.0"
14
14
  gemspec.add_dependency "wmi-lite", "~> 1.0"
15
15
  gemspec.add_dependency "win32-taskscheduler", "~> 2.0"
16
16
  gemspec.add_dependency "iso8601", ">= 0.12.1", "< 0.14" # validate 0.14 when it comes out
17
- gemspec.add_dependency "win32-certstore", "~> 0.3"
17
+ gemspec.add_dependency "win32-certstore", "~> 0.5" # 0.5+ required for specifying user vs. system store
18
18
  gemspec.extensions << "ext/win32-eventlog/Rakefile"
19
19
  gemspec.files += Dir.glob("{distro,ext}/**/*")
20
20
 
@@ -20,8 +20,8 @@ class Chef
20
20
  # renamed from Chef Visibility in 2017, so should capture all modern versions of the audit cookbook.
21
21
  audit_cookbook_present = defined?(::Reporter::ChefAutomate)
22
22
 
23
- logger.info("#{self.class}##{__method__}: #{Inspec::Dist::PRODUCT_NAME} profiles? #{inspec_profiles.any?}")
24
- logger.info("#{self.class}##{__method__}: audit cookbook? #{audit_cookbook_present}")
23
+ logger.debug("#{self.class}##{__method__}: #{Inspec::Dist::PRODUCT_NAME} profiles? #{inspec_profiles.any?}")
24
+ logger.debug("#{self.class}##{__method__}: audit cookbook? #{audit_cookbook_present}")
25
25
 
26
26
  inspec_profiles.any? && !audit_cookbook_present
27
27
  end
@@ -47,7 +47,7 @@ class Chef
47
47
  registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending')
48
48
  elsif platform?("ubuntu")
49
49
  # This should work for Debian as well if update-notifier-common happens to be installed. We need an API for that.
50
- File.exists?("/var/run/reboot-required")
50
+ File.exist?("/var/run/reboot-required")
51
51
  else
52
52
  false
53
53
  end
@@ -33,7 +33,7 @@ class Chef
33
33
  module ClassMethods
34
34
  # We want to mix these in as class methods
35
35
  def writable?(path)
36
- ::File.exists?(path) && Chef::ReservedNames::Win32::File.file_access_check(
36
+ ::File.exist?(path) && Chef::ReservedNames::Win32::File.file_access_check(
37
37
  path, Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE
38
38
  )
39
39
  end
@@ -136,7 +136,7 @@ class Chef
136
136
  end
137
137
 
138
138
  def should_update_dacl?
139
- return true unless ::File.exists?(file) || ::File.symlink?(file)
139
+ return true unless ::File.exist?(file) || ::File.symlink?(file)
140
140
 
141
141
  dacl = target_dacl
142
142
  existing_dacl = existing_descriptor.dacl
@@ -170,7 +170,7 @@ class Chef
170
170
  end
171
171
 
172
172
  def should_update_group?
173
- return true unless ::File.exists?(file) || ::File.symlink?(file)
173
+ return true unless ::File.exist?(file) || ::File.symlink?(file)
174
174
 
175
175
  (group = target_group) && (group != existing_descriptor.group)
176
176
  end
@@ -190,7 +190,7 @@ class Chef
190
190
  end
191
191
 
192
192
  def should_update_owner?
193
- return true unless ::File.exists?(file) || ::File.symlink?(file)
193
+ return true unless ::File.exist?(file) || ::File.symlink?(file)
194
194
 
195
195
  (owner = target_owner) && (owner != existing_descriptor.owner)
196
196
  end
@@ -79,7 +79,7 @@ class Chef
79
79
 
80
80
  file_path_array = File.split(path)
81
81
  file_name = file_path_array.pop
82
- if File.exists?(file) && File.writable?(file)
82
+ if File.exist?(file) && File.writable?(file)
83
83
  FileUtils.mv(
84
84
  file,
85
85
  File.join(create_cache_path(File.join(file_path_array), true), file_name)
@@ -112,7 +112,7 @@ class Chef
112
112
  }
113
113
  )
114
114
  cache_path = create_cache_path(path, false)
115
- raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.exists?(cache_path)
115
+ raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.exist?(cache_path)
116
116
 
117
117
  if read
118
118
  File.read(cache_path)
@@ -139,7 +139,7 @@ class Chef
139
139
  }
140
140
  )
141
141
  cache_path = create_cache_path(path, false)
142
- if File.exists?(cache_path)
142
+ if File.exist?(cache_path)
143
143
  File.unlink(cache_path)
144
144
  end
145
145
  true
@@ -186,7 +186,7 @@ class Chef
186
186
  }
187
187
  )
188
188
  full_path = create_cache_path(path, false)
189
- if File.exists?(full_path)
189
+ if File.exist?(full_path)
190
190
  true
191
191
  else
192
192
  false
@@ -66,7 +66,7 @@ class Chef
66
66
 
67
67
  @snippet ||= begin
68
68
  if (file = parse_source) && (line = parse_line(file))
69
- return nil unless ::File.exists?(file)
69
+ return nil unless ::File.exist?(file)
70
70
 
71
71
  lines = IO.readlines(file)
72
72
 
@@ -51,7 +51,7 @@ class Chef
51
51
  end
52
52
 
53
53
  def build_report_dir
54
- unless File.exists?(config[:path])
54
+ unless File.exist?(config[:path])
55
55
  FileUtils.mkdir_p(config[:path])
56
56
  File.chmod(00700, config[:path])
57
57
  end
@@ -217,6 +217,16 @@ class Chef
217
217
  description: "Execute the bootstrap via sudo with password.",
218
218
  boolean: false
219
219
 
220
+ # runtime - su user
221
+ option :su_user,
222
+ long: "--su-user NAME",
223
+ description: "The su - USER name to perform bootstrap command using a non-root user."
224
+
225
+ # runtime - su user password
226
+ option :su_password,
227
+ long: "--su-password PASSWORD",
228
+ description: "The su USER password for authentication."
229
+
220
230
  # runtime - client_builder
221
231
  option :chef_node_name,
222
232
  short: "-N NAME",
@@ -591,13 +601,31 @@ class Chef
591
601
  def perform_bootstrap(remote_bootstrap_script_path)
592
602
  ui.info("Bootstrapping #{ui.color(server_name, :bold)}")
593
603
  cmd = bootstrap_command(remote_bootstrap_script_path)
594
- r = connection.run_command(cmd) do |data|
604
+ bootstrap_run_command(cmd)
605
+ end
606
+
607
+ # Actual bootstrap command to be run on the node.
608
+ # Handles recursive calls if su USER failed to authenticate.
609
+ def bootstrap_run_command(cmd)
610
+ r = connection.run_command(cmd) do |data, channel|
595
611
  ui.msg("#{ui.color(" [#{connection.hostname}]", :cyan)} #{data}")
612
+ channel.send_data("#{config[:su_password] || config[:connection_password]}\n") if data.match?("Password:")
596
613
  end
614
+
597
615
  if r.exit_status != 0
598
616
  ui.error("The following error occurred on #{server_name}:")
599
- ui.error(r.stderr)
600
- exit 1
617
+ ui.error("#{r.stdout} #{r.stderr}".strip)
618
+ exit(r.exit_status)
619
+ end
620
+ rescue Train::UserError => e
621
+ limit ||= 0
622
+ if e.reason == :bad_su_user_password && limit < 3
623
+ limit += 1
624
+ ui.warn("Failed to authenticate su - #{config[:su_user]} to #{server_name}")
625
+ config[:su_password] = ui.ask("Enter password for su - #{config[:su_user]}@#{server_name}:", echo: false)
626
+ retry
627
+ else
628
+ raise
601
629
  end
602
630
  end
603
631
 
@@ -1082,7 +1110,17 @@ class Chef
1082
1110
  if connection.windows?
1083
1111
  "cmd.exe /C #{remote_path}"
1084
1112
  else
1085
- "sh #{remote_path}"
1113
+ cmd = "sh #{remote_path}"
1114
+
1115
+ if config[:su_user]
1116
+ # su - USER is subject to required an interactive console
1117
+ # Otherwise, it will raise: su: must be run from a terminal
1118
+ set_transport_options(pty: true)
1119
+ cmd = "su - #{config[:su_user]} -c '#{cmd}'"
1120
+ cmd = "sudo " << cmd if config[:use_sudo]
1121
+ end
1122
+
1123
+ cmd
1086
1124
  end
1087
1125
  end
1088
1126
 
@@ -1137,6 +1175,18 @@ class Chef
1137
1175
 
1138
1176
  timeout.to_i
1139
1177
  end
1178
+
1179
+ # Train::Transports::SSH::Connection#transport_options
1180
+ # Append the options to connection transport_options
1181
+ #
1182
+ # @param opts [Hash] the opts to be added to connection transport_options.
1183
+ # @return [Hash] transport_options if the opts contains any option to be set.
1184
+ #
1185
+ def set_transport_options(opts)
1186
+ return unless opts.is_a?(Hash) || !opts.empty?
1187
+
1188
+ connection&.connection&.transport_options&.merge! opts
1189
+ end
1140
1190
  end
1141
1191
  end
1142
1192
  end
@@ -446,8 +446,8 @@ class Chef
446
446
  # requested new_resource.version constraints
447
447
  logger.trace("#{new_resource} has no existing installed version. Installing install #{candidate_version}")
448
448
  target_version_array.push(candidate_version)
449
- elsif version_equals?(current_version, new_version)
450
- # this is a short-circuit to avoid needing to (expensively) query the candidate_version which must come later
449
+ elsif !use_magic_version? && version_equals?(current_version, new_version)
450
+ # this is a short-circuit (mostly for the rubygems provider) to avoid needing to expensively query the candidate_version which must come later
451
451
  logger.trace("#{new_resource} #{package_name} #{new_version} is already installed")
452
452
  target_version_array.push(nil)
453
453
  elsif candidate_version.nil?
@@ -64,7 +64,7 @@ def version_tuple(versionstr):
64
64
  tmp = versionstr[colon_index + 1:dash_index]
65
65
  if tmp != '':
66
66
  v = tmp
67
- arch_index = versionstr.find('.', dash_index)
67
+ arch_index = versionstr.rfind('.', dash_index)
68
68
  if arch_index > 0:
69
69
  r = versionstr[dash_index + 1:arch_index]
70
70
  else:
data/lib/chef/resource.rb CHANGED
@@ -1062,6 +1062,7 @@ class Chef
1062
1062
  # action for the resource.
1063
1063
  #
1064
1064
  # @param name [Symbol] The action name to define.
1065
+ # @param description [String] optional description for the action
1065
1066
  # @param recipe_block The recipe to run when the action is taken. This block
1066
1067
  # takes no parameters, and will be evaluated in a new context containing:
1067
1068
  #
@@ -1071,14 +1072,37 @@ class Chef
1071
1072
  #
1072
1073
  # @return The Action class implementing the action
1073
1074
  #
1074
- def self.action(action, &recipe_block)
1075
+ def self.action(action, description: nil, &recipe_block)
1075
1076
  action = action.to_sym
1076
1077
  declare_action_class
1077
1078
  action_class.action(action, &recipe_block)
1078
1079
  self.allowed_actions += [ action ]
1080
+ # Accept any non-nil description, which will correctly override
1081
+ # any specific inherited description.
1082
+ action_descriptions[action] = description unless description.nil?
1079
1083
  default_action action if Array(default_action) == [:nothing]
1080
1084
  end
1081
1085
 
1086
+ # Retrieve the description for a resource's action, if
1087
+ # any description has been included in the definition.
1088
+ #
1089
+ # @param action [Symbol,String] the action name
1090
+ # @return the description of the action provided, or nil if no description
1091
+ # was defined
1092
+ def self.action_description(action)
1093
+ action_descriptions[action.to_sym]
1094
+ end
1095
+
1096
+ # @api private
1097
+ #
1098
+ # @return existing action description hash, or newly-initialized
1099
+ # hash containing action descriptions inherited from parent Resource,
1100
+ # if any.
1101
+ def self.action_descriptions
1102
+ @action_descriptions ||=
1103
+ superclass.respond_to?(:action_descriptions) ? superclass.action_descriptions.dup : { nothing: nil }
1104
+ end
1105
+
1082
1106
  # Define a method to load up this resource's properties with the current
1083
1107
  # actual values.
1084
1108
  #
@@ -1196,9 +1220,9 @@ class Chef
1196
1220
  #
1197
1221
 
1198
1222
  # FORBIDDEN_IVARS do not show up when the resource is converted to JSON (ie. hidden from data_collector and sending to the chef server via #to_json/to_h/as_json/inspect)
1199
- FORBIDDEN_IVARS = %i{@run_context @logger @not_if @only_if @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner}.freeze
1223
+ FORBIDDEN_IVARS = %i{@run_context @logger @not_if @only_if @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner @action_descriptions}.freeze
1200
1224
  # HIDDEN_IVARS do not show up when the resource is displayed to the user as text (ie. in the error inspector output via #to_text)
1201
- HIDDEN_IVARS = %i{@allowed_actions @resource_name @source_line @run_context @logger @name @not_if @only_if @elapsed_time @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner}.freeze
1225
+ HIDDEN_IVARS = %i{@allowed_actions @resource_name @source_line @run_context @logger @name @not_if @only_if @elapsed_time @enclosing_provider @description @introduced @examples @validation_message @deprecated @default_description @skip_docs @executed_by_runner @action_descriptions}.freeze
1202
1226
 
1203
1227
  include Chef::Mixin::ConvertToClassName
1204
1228
  extend Chef::Mixin::ConvertToClassName
@@ -76,7 +76,7 @@ class Chef
76
76
  default: "MY", equal_to: ["TRUSTEDPUBLISHER", "TrustedPublisher", "CLIENTAUTHISSUER", "REMOTE DESKTOP", "ROOT", "TRUSTEDDEVICES", "WEBHOSTING", "CA", "AUTHROOT", "TRUSTEDPEOPLE", "MY", "SMARTCARDROOT", "TRUST", "DISALLOWED"]
77
77
 
78
78
  property :user_store, [TrueClass, FalseClass],
79
- description: "Use the user store of the local machine store if set to false.",
79
+ description: "Use the `CurrentUser` store instead of the default `LocalMachine` store. Note: Prior to #{ChefUtils::Dist::Infra::CLIENT}. 16.10 this property was ignored.",
80
80
  default: false
81
81
 
82
82
  property :cert_path, String,
@@ -119,7 +119,7 @@ class Chef
119
119
  code_script << acl_script(hash)
120
120
  guard_script << cert_exists_script(hash)
121
121
 
122
- powershell_script "setting the acls on #{new_resource.source} in #{cert_location}\\#{new_resource.store_name}" do
122
+ powershell_script "setting the acls on #{new_resource.source} in #{ps_cert_location}\\#{new_resource.store_name}" do
123
123
  convert_boolean_return true
124
124
  code code_script
125
125
  only_if guard_script
@@ -161,25 +161,47 @@ class Chef
161
161
  end
162
162
 
163
163
  action_class do
164
+
165
+ CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000
166
+ CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000
167
+
164
168
  def add_cert(cert_obj)
165
- store = ::Win32::Certstore.open(new_resource.store_name)
169
+ store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
166
170
  store.add(cert_obj)
167
171
  end
168
172
 
169
173
  def add_pfx_cert
170
174
  exportable = new_resource.exportable ? 1 : 0
171
- store = ::Win32::Certstore.open(new_resource.store_name)
175
+ store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
172
176
  store.add_pfx(new_resource.source, new_resource.pfx_password, exportable)
173
177
  end
174
178
 
175
179
  def delete_cert
176
- store = ::Win32::Certstore.open(new_resource.store_name)
177
- store.delete(new_resource.source)
180
+ store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
181
+ store.delete(resolve_thumbprint(new_resource.source))
178
182
  end
179
183
 
180
184
  def fetch_cert
181
- store = ::Win32::Certstore.open(new_resource.store_name)
182
- store.get(new_resource.source)
185
+ store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
186
+ store.get(resolve_thumbprint(new_resource.source))
187
+ end
188
+
189
+ # Thumbprints should be exactly 40 Hex characters
190
+ def valid_thumbprint?(string)
191
+ string.scan(/\H/).empty? && string.length == 40
192
+ end
193
+
194
+ def get_thumbprint(store_name, location, source)
195
+ <<-GETTHUMBPRINTCODE
196
+ $content = Get-ChildItem -Path Cert:\\#{location}\\#{store_name} | Where-Object {$_.Subject -Match "#{source}"} | Select-Object Thumbprint
197
+ $content.thumbprint
198
+ GETTHUMBPRINTCODE
199
+ end
200
+
201
+ def resolve_thumbprint(thumbprint)
202
+ return thumbprint if valid_thumbprint?(thumbprint)
203
+
204
+ powershell_exec!(get_thumbprint(new_resource.store_name, ps_cert_location, new_resource.source)).result
183
205
  end
184
206
 
185
207
  # Checks whether a certificate with the given thumbprint
@@ -187,9 +209,11 @@ class Chef
187
209
  # If the certificate is not present, verify_cert returns a String: "Certificate not found"
188
210
  # But if it is present but expired, it returns a Boolean: false
189
211
  # Otherwise, it returns a Boolean: true
212
+ # updated this method to accept either a subject name or a thumbprint - 1/29/2021
213
+
190
214
  def verify_cert(thumbprint = new_resource.source)
191
- store = ::Win32::Certstore.open(new_resource.store_name)
192
- store.valid?(thumbprint)
215
+ store = ::Win32::Certstore.open(new_resource.store_name, store_location: native_cert_location)
216
+ store.valid?(resolve_thumbprint(thumbprint))
193
217
  end
194
218
 
195
219
  def show_or_store_cert(cert_obj)
@@ -230,13 +254,19 @@ class Chef
230
254
  out_file.close
231
255
  end
232
256
 
233
- def cert_location
234
- @location ||= new_resource.user_store ? "CurrentUser" : "LocalMachine"
257
+ # this array structure is solving 2 problems. The first is that we need to have support for both the CurrentUser AND LocalMachine stores
258
+ # Secondly, we need to pass the proper constant name for each store to win32-certstore but also pass the short name to powershell scripts used here
259
+ def ps_cert_location
260
+ new_resource.user_store ? "CurrentUser" : "LocalMachine"
261
+ end
262
+
263
+ def native_cert_location
264
+ new_resource.user_store ? CERT_SYSTEM_STORE_CURRENT_USER : CERT_SYSTEM_STORE_LOCAL_MACHINE
235
265
  end
236
266
 
237
267
  def cert_script(persist)
238
268
  cert_script = "$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2"
239
- file = Chef::Util::PathHelper.cleanpath(new_resource.source)
269
+ file = Chef::Util::PathHelper.cleanpath(new_resource.source, ps_cert_location)
240
270
  cert_script << " \"#{file}\""
241
271
  if ::File.extname(file.downcase) == ".pfx"
242
272
  cert_script << ", \"#{new_resource.pfx_password}\""
@@ -252,14 +282,14 @@ class Chef
252
282
  def cert_exists_script(hash)
253
283
  <<-EOH
254
284
  $hash = #{hash}
255
- Test-Path "Cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
285
+ Test-Path "Cert:\\#{ps_cert_location}\\#{new_resource.store_name}\\$hash"
256
286
  EOH
257
287
  end
258
288
 
259
289
  def within_store_script
260
290
  inner_script = yield "$store"
261
291
  <<-EOH
262
- $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{cert_location})
292
+ $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{ps_cert_location})
263
293
  $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
264
294
  #{inner_script}
265
295
  $store.Close()
@@ -273,7 +303,7 @@ class Chef
273
303
  # and from https://msdn.microsoft.com/en-us/library/windows/desktop/bb204778(v=vs.85).aspx
274
304
  set_acl_script = <<-EOH
275
305
  $hash = #{hash}
276
- $storeCert = Get-ChildItem "cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
306
+ $storeCert = Get-ChildItem "cert:\\#{ps_cert_location}\\#{new_resource.store_name}\\$hash"
277
307
  if ($storeCert -eq $null) { throw 'no key exists.' }
278
308
  $keyname = $storeCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
279
309
  if ($keyname -eq $null) { throw 'no private key exists.' }
@@ -340,7 +370,7 @@ class Chef
340
370
  if verify_cert(thumbprint) == true
341
371
  Chef::Log.debug("Certificate is already present")
342
372
  else
343
- converge_by("Adding certificate #{new_resource.source} into Store #{new_resource.store_name}") do
373
+ converge_by("Adding certificate #{new_resource.source} into #{ps_cert_location} Store #{new_resource.store_name}") do
344
374
  if is_pfx
345
375
  add_pfx_cert
346
376
  else
@@ -41,7 +41,11 @@ class Chef
41
41
  data[:description] = resource.description
42
42
  # data[:deprecated] = resource.deprecated || false
43
43
  data[:default_action] = resource.default_action
44
- data[:actions] = resource.allowed_actions
44
+ data[:actions] = {}
45
+ resource.allowed_actions.each do |action|
46
+ data[:actions][action] = resource.action_description(action)
47
+ end
48
+
45
49
  data[:examples] = resource.examples
46
50
  data[:introduced] = resource.introduced
47
51
  data[:preview] = resource.preview_resource
data/lib/chef/shell.rb CHANGED
@@ -352,13 +352,13 @@ module Shell
352
352
  puts "loading configuration: #{config_msg}"
353
353
 
354
354
  # load the config (if we have one)
355
- if !config[:config_file].nil?
355
+ unless config[:config_file].nil?
356
356
  if File.exist?(config[:config_file]) && File.readable?(config[:config_file])
357
357
  Chef::Config.from_file(config[:config_file])
358
358
  end
359
359
 
360
360
  # even if we couldn't load that, we need to tell Chef::Config what
361
- # the file was so it sets confdir and d_dir and such properly
361
+ # the file was so it sets conf dir and d_dir and such properly
362
362
  Chef::Config[:config_file] = config[:config_file]
363
363
 
364
364
  # now attempt to load any relevant dot-dirs
@@ -105,7 +105,7 @@ class Chef::Util::DSC
105
105
  # The name may not be null or empty, and should start with a letter.
106
106
  def validate_configuration_name!(configuration_name)
107
107
  if !!(configuration_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
108
- raise ArgumentError, 'Configuration `#{configuration_name}` is not a valid PowerShell cmdlet name'
108
+ raise ArgumentError, "Configuration `#{configuration_name}` is not a valid PowerShell cmdlet name"
109
109
  end
110
110
  end
111
111
 
data/lib/chef/version.rb CHANGED
@@ -23,7 +23,7 @@ require_relative "version_string"
23
23
 
24
24
  class Chef
25
25
  CHEF_ROOT = File.expand_path("..", __dir__)
26
- VERSION = Chef::VersionString.new("16.9.32")
26
+ VERSION = Chef::VersionString.new("16.10.8")
27
27
  end
28
28
 
29
29
  #
@@ -223,6 +223,10 @@ module ResourceActionSpec
223
223
  ActionJackson.succeeded = ActionJackson.ruby_block_converged
224
224
  end
225
225
 
226
+ action :test1, description: "Original description" do
227
+ true
228
+ end
229
+
226
230
  def foo_public
227
231
  "foo_public!"
228
232
  end
@@ -293,7 +297,12 @@ module ResourceActionSpec
293
297
  ActionJackalope.jackalope_ran = :access_attribute
294
298
  ActionJackalope.succeeded = ActionJackson.succeeded
295
299
  end
300
+
301
+ action :test1, description: "An old action with a new description" do
302
+ super
303
+ end
296
304
  end
305
+
297
306
  before do
298
307
  ActionJackalope.jackalope_ran = nil
299
308
  ActionJackalope.load_current_resource_ran = nil
@@ -344,6 +353,11 @@ module ResourceActionSpec
344
353
  expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
345
354
  end
346
355
 
356
+ it "allows overridden action to have a description separate from the action defined in the base resource" do
357
+ expect(ActionJackson.action_description(:test1)).to eql "Original description"
358
+ expect(ActionJackalope.action_description(:test1)).to eql "An old action with a new description"
359
+ end
360
+
347
361
  it "non-overridden actions run and can access overridden and non-overridden variables (but not necessarily new ones)" do
348
362
  converge do
349
363
  action_jackalope "hi" do
@@ -57,12 +57,12 @@ describe Chef::DSL::RebootPending do
57
57
  end
58
58
 
59
59
  it "should return true if /var/run/reboot-required exists" do
60
- allow(File).to receive(:exists?).with("/var/run/reboot-required").and_return(true)
60
+ allow(File).to receive(:exist?).with("/var/run/reboot-required").and_return(true)
61
61
  expect(recipe.reboot_pending?).to be_truthy
62
62
  end
63
63
 
64
64
  it "should return false if /var/run/reboot-required does not exist" do
65
- allow(File).to receive(:exists?).with("/var/run/reboot-required").and_return(false)
65
+ allow(File).to receive(:exist?).with("/var/run/reboot-required").and_return(false)
66
66
  expect(recipe.reboot_pending?).to be_falsey
67
67
  end
68
68
  end
@@ -115,7 +115,7 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
115
115
  # fake code to run through #recipe_snippet
116
116
  source_file = [ "if true", "var = non_existent", "end" ]
117
117
  allow(IO).to receive(:readlines).and_return(source_file)
118
- allow(File).to receive(:exists?).and_return(true)
118
+ allow(File).to receive(:exist?).and_return(true)
119
119
  end
120
120
 
121
121
  it "parses a Windows path" do
@@ -141,7 +141,7 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
141
141
 
142
142
  context "when the recipe file does not exist" do
143
143
  before do
144
- allow(File).to receive(:exists?).and_return(false)
144
+ allow(File).to receive(:exist?).and_return(false)
145
145
  allow(IO).to receive(:readlines).and_raise(Errno::ENOENT)
146
146
  end
147
147
 
@@ -1726,7 +1726,8 @@ describe Chef::Knife::Bootstrap do
1726
1726
 
1727
1727
  describe "#perform_bootstrap" do
1728
1728
  let(:exit_status) { 0 }
1729
- let(:result_mock) { double("result", exit_status: exit_status, stderr: "A message") }
1729
+ let(:stdout) { "" }
1730
+ let(:result_mock) { double("result", exit_status: exit_status, stderr: "A message", stdout: stdout) }
1730
1731
 
1731
1732
  before do
1732
1733
  allow(connection).to receive(:hostname).and_return "testhost"
@@ -1739,12 +1740,13 @@ describe Chef::Knife::Bootstrap do
1739
1740
  expect(connection)
1740
1741
  .to receive(:run_command)
1741
1742
  .with("sh /path.sh")
1742
- .and_yield("output here")
1743
+ .and_yield("output here", nil)
1743
1744
  .and_return result_mock
1744
1745
 
1745
1746
  expect(knife.ui).to receive(:msg).with(/testhost/)
1746
1747
  knife.perform_bootstrap("/path.sh")
1747
1748
  end
1749
+
1748
1750
  context "when the remote command fails" do
1749
1751
  let(:exit_status) { 1 }
1750
1752
  it "shows an error and exits" do
@@ -1756,6 +1758,25 @@ describe Chef::Knife::Bootstrap do
1756
1758
  expect { knife.perform_bootstrap("/path.sh") }.to raise_error(SystemExit)
1757
1759
  end
1758
1760
  end
1761
+
1762
+ context "when the remote command failed due to su auth error" do
1763
+ let(:exit_status) { 1 }
1764
+ let(:stdout) { "su: Authentication failure" }
1765
+ let(:connection_obj) { double("connection", transport_options: {}) }
1766
+ it "shows an error and exits" do
1767
+ allow(connection).to receive(:connection).and_return(connection_obj)
1768
+ expect(knife.ui).to receive(:info).with(/Bootstrapping.*/)
1769
+ expect(knife).to receive(:bootstrap_command)
1770
+ .with("/path.sh")
1771
+ .and_return("su - USER -c 'sh /path.sh'")
1772
+ expect(connection)
1773
+ .to receive(:run_command)
1774
+ .with("su - USER -c 'sh /path.sh'")
1775
+ .and_yield("output here", nil)
1776
+ .and_raise(Train::UserError)
1777
+ expect { knife.perform_bootstrap("/path.sh") }.to raise_error(Train::UserError)
1778
+ end
1779
+ end
1759
1780
  end
1760
1781
 
1761
1782
  describe "#connect!" do
@@ -1964,7 +1985,25 @@ describe Chef::Knife::Bootstrap do
1964
1985
  context "under Linux" do
1965
1986
  let(:linux_test) { true }
1966
1987
  it "prefixes the command to run under sh" do
1967
- expect(knife.bootstrap_command("bootstrap")).to eq "sh bootstrap"
1988
+ expect(knife.bootstrap_command("bootstrap.sh")).to eq "sh bootstrap.sh"
1989
+ end
1990
+
1991
+ context "with --su-user option" do
1992
+ let(:connection_obj) { double("connection", transport_options: {}) }
1993
+ before do
1994
+ knife.config[:su_user] = "root"
1995
+ allow(connection).to receive(:connection).and_return(connection_obj)
1996
+ end
1997
+ it "prefixes the command to run using su -USER -c" do
1998
+ expect(knife.bootstrap_command("bootstrap.sh")).to eq "su - #{knife.config[:su_user]} -c 'sh bootstrap.sh'"
1999
+ expect(connection_obj.transport_options.key?(:pty)).to eq true
2000
+ end
2001
+
2002
+ it "sudo appended if --sudo option enabled" do
2003
+ knife.config[:use_sudo] = true
2004
+ expect(knife.bootstrap_command("bootstrap.sh")).to eq "sudo su - #{knife.config[:su_user]} -c 'sh bootstrap.sh'"
2005
+ expect(connection_obj.transport_options.key?(:pty)).to eq true
2006
+ end
1968
2007
  end
1969
2008
  end
1970
2009
  end
@@ -46,7 +46,9 @@ describe Chef::Knife::SupermarketShare do
46
46
 
47
47
  allow(@knife).to receive(:shell_out!).and_return(true)
48
48
  @stdout = StringIO.new
49
+ @stderr = StringIO.new
49
50
  allow(@knife.ui).to receive(:stdout).and_return(@stdout)
51
+ allow(@knife.ui).to receive(:stderr).and_return(@stderr)
50
52
  end
51
53
 
52
54
  describe "run" do
@@ -140,7 +142,9 @@ describe Chef::Knife::SupermarketShare do
140
142
  before do
141
143
  allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return("/var/tmp/dummy")
142
144
  @knife.config = { dry_run: true }
143
- allow(@knife).to receive_message_chain(:shell_out!, :stdout).and_return("file")
145
+ @so = instance_double("Mixlib::ShellOut")
146
+ allow(@knife).to receive(:shell_out!).and_return(@so)
147
+ allow(@so).to receive(:stdout).and_return("file")
144
148
  end
145
149
 
146
150
  it "should list files in the tarball" do
@@ -151,7 +155,6 @@ describe Chef::Knife::SupermarketShare do
151
155
  end
152
156
 
153
157
  it "does not upload the cookbook" do
154
- allow(@knife).to receive(:shell_out!).and_return(true)
155
158
  expect(@knife).not_to receive(:do_upload)
156
159
  @knife.run
157
160
  end
@@ -164,10 +167,6 @@ describe Chef::Knife::SupermarketShare do
164
167
  @upload_response = double("Net::HTTPResponse")
165
168
  allow(Chef::CookbookSiteStreamingUploader).to receive(:post).and_return(@upload_response)
166
169
 
167
- @stdout = StringIO.new
168
- @stderr = StringIO.new
169
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
170
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
171
170
  allow(File).to receive(:open).and_return(true)
172
171
  end
173
172
 
@@ -19,11 +19,17 @@ require "spec_helper"
19
19
 
20
20
  # NOTE: most of the tests of this functionality are baked into the func tests for the dnf package provider
21
21
 
22
- describe Chef::Provider::Package::Dnf::PythonHelper do
22
+ # run this test only for following platforms.
23
+ exclude_test = !(%w{rhel fedora amazon}.include?(ohai[:platform_family]) && File.exist?("/usr/bin/dnf"))
24
+ describe Chef::Provider::Package::Dnf::PythonHelper, :requires_root, external: exclude_test do
23
25
  let(:helper) { Chef::Provider::Package::Dnf::PythonHelper.instance }
24
26
 
25
27
  it "propagates stacktraces on stderr from the forked subprocess", :rhel do
26
28
  allow(helper).to receive(:dnf_command).and_return("ruby -e 'raise \"your hands in the air\"'")
27
29
  expect { helper.package_query(:whatprovides, "tcpdump") }.to raise_error(/your hands in the air/)
28
30
  end
31
+
32
+ it "compares EVRAs with dots in the release correctly" do
33
+ expect(helper.compare_versions("0:1.8.29-6.el8.x86_64", "0:1.8.29-6.el8_3.1.x86_64")).to eql(-1)
34
+ end
29
35
  end
@@ -28,7 +28,11 @@ class DummyResource < Chef::Resource
28
28
  introduced "14.0"
29
29
  property :first, String, description: "My First Property", introduced: "14.0"
30
30
 
31
- action :dummy do
31
+ action :dummy, description: "Dummy action" do
32
+ return true
33
+ end
34
+
35
+ action :dummy_no_desc do
32
36
  return true
33
37
  end
34
38
  end
@@ -39,7 +43,8 @@ describe Chef::ResourceInspector do
39
43
 
40
44
  it "returns a hash with required data" do
41
45
  expect(subject[:description]).to eq "A dummy resource"
42
- expect(subject[:actions]).to match_array %i{nothing dummy}
46
+ expect(subject[:actions]).to eq({ nothing: nil, dummy: "Dummy action",
47
+ dummy_no_desc: nil })
43
48
  end
44
49
 
45
50
  context "excluding built in properties" do
@@ -1162,6 +1162,52 @@ describe Chef::Resource do
1162
1162
  end
1163
1163
  end
1164
1164
 
1165
+ describe "#action_description" do
1166
+ class TestResource < ::Chef::Resource
1167
+ action :symbol_action, description: "a symbol test" do; end
1168
+ action "string_action", description: "a string test" do; end
1169
+ action :base_action0 do; end
1170
+ action :base_action1, description: "unmodified base action 1 desc" do; end
1171
+ action :base_action2, description: "unmodified base action 2 desc" do; end
1172
+ action :base_action3, description: "unmodified base action 3 desc" do; end
1173
+ end
1174
+
1175
+ it "returns nil when no description was provided for the action" do
1176
+ expect(TestResource.action_description(:base_action0)).to eql(nil)
1177
+ end
1178
+
1179
+ context "when action definition is a string" do
1180
+ it "returns the description whether a symbol or string is used to look it up" do
1181
+ expect(TestResource.action_description("string_action")).to eql("a string test")
1182
+ expect(TestResource.action_description(:string_action)).to eql("a string test")
1183
+ end
1184
+ end
1185
+
1186
+ context "when action definition is a symbol" do
1187
+ it "returns the description whether a symbol or string is used to look up" do
1188
+ expect(TestResource.action_description("symbol_action")).to eql("a symbol test")
1189
+ expect(TestResource.action_description(:symbol_action)).to eql("a symbol test")
1190
+ end
1191
+ end
1192
+
1193
+ context "when inheriting from an existing resource" do
1194
+ class TestResourceChild < TestResource
1195
+ action :base_action2, description: "modified base action 2 desc" do; end
1196
+ action :base_action3 do; end
1197
+ end
1198
+
1199
+ it "returns original description when a described action is not overridden in child resource" do
1200
+ expect(TestResourceChild.action_description(:base_action1)).to eq "unmodified base action 1 desc"
1201
+ end
1202
+ it "returns original description when the child resource overrides an inherited action but NOT its description" do
1203
+ expect(TestResourceChild.action_description(:base_action3)).to eq "unmodified base action 3 desc"
1204
+ end
1205
+ it "returns new description when the child resource overrides an inherited action and its description" do
1206
+ expect(TestResourceChild.action_description(:base_action2)).to eq "modified base action 2 desc"
1207
+ end
1208
+ end
1209
+ end
1210
+
1165
1211
  describe ".default_action" do
1166
1212
  let(:default_action) {}
1167
1213
  let(:resource_class) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.9.32
4
+ version: 16.10.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Jacob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-27 00:00:00.000000000 Z
11
+ date: 2021-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-config
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 16.9.32
19
+ version: 16.10.8
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 16.9.32
26
+ version: 16.10.8
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: chef-utils
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 16.9.32
33
+ version: 16.10.8
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 16.9.32
40
+ version: 16.10.8
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: train-core
43
43
  requirement: !ruby/object:Gem::Requirement