chef 17.2.29 → 17.3.48

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -3
  3. data/chef.gemspec +1 -0
  4. data/lib/chef/client.rb +1 -1
  5. data/lib/chef/data_bag.rb +1 -2
  6. data/lib/chef/data_bag_item.rb +1 -2
  7. data/lib/chef/deprecated.rb +10 -4
  8. data/lib/chef/dsl.rb +1 -0
  9. data/lib/chef/dsl/render_helpers.rb +44 -0
  10. data/lib/chef/dsl/secret.rb +64 -0
  11. data/lib/chef/dsl/toml.rb +116 -0
  12. data/lib/chef/dsl/universal.rb +5 -0
  13. data/lib/chef/exceptions.rb +22 -0
  14. data/lib/chef/handler/slow_report.rb +1 -1
  15. data/lib/chef/json_compat.rb +1 -1
  16. data/lib/chef/policy_builder/policyfile.rb +88 -45
  17. data/lib/chef/provider/file.rb +2 -2
  18. data/lib/chef/provider/lwrp_base.rb +1 -1
  19. data/lib/chef/provider/package/habitat.rb +168 -0
  20. data/lib/chef/provider/package/powershell.rb +5 -0
  21. data/lib/chef/providers.rb +1 -0
  22. data/lib/chef/resource/chef_client_config.rb +7 -2
  23. data/lib/chef/resource/chef_client_cron.rb +1 -1
  24. data/lib/chef/resource/chef_client_launchd.rb +1 -1
  25. data/lib/chef/resource/chef_client_scheduled_task.rb +1 -1
  26. data/lib/chef/resource/chef_client_systemd_timer.rb +1 -1
  27. data/lib/chef/resource/chef_client_trusted_certificate.rb +2 -2
  28. data/lib/chef/resource/chef_vault_secret.rb +2 -2
  29. data/lib/chef/resource/dsc_resource.rb +1 -1
  30. data/lib/chef/resource/execute.rb +3 -3
  31. data/lib/chef/resource/gem_package.rb +2 -1
  32. data/lib/chef/resource/habitat/_habitat_shared.rb +28 -0
  33. data/lib/chef/resource/habitat/habitat_package.rb +129 -0
  34. data/lib/chef/resource/habitat/habitat_sup.rb +329 -0
  35. data/lib/chef/resource/habitat/habitat_sup_systemd.rb +67 -0
  36. data/lib/chef/resource/habitat/habitat_sup_windows.rb +90 -0
  37. data/lib/chef/resource/habitat_config.rb +107 -0
  38. data/lib/chef/resource/habitat_install.rb +247 -0
  39. data/lib/chef/resource/habitat_service.rb +451 -0
  40. data/lib/chef/resource/habitat_user_toml.rb +92 -0
  41. data/lib/chef/resource/lwrp_base.rb +1 -1
  42. data/lib/chef/resource/support/HabService.dll.config.erb +19 -0
  43. data/lib/chef/resource/support/client.erb +8 -1
  44. data/lib/chef/resource/support/sup.toml.erb +179 -0
  45. data/lib/chef/resource/windows_defender.rb +163 -0
  46. data/lib/chef/resource/windows_defender_exclusion.rb +125 -0
  47. data/lib/chef/resource/windows_printer.rb +78 -44
  48. data/lib/chef/resource/windows_printer_port.rb +1 -1
  49. data/lib/chef/resource/windows_update_settings.rb +259 -0
  50. data/lib/chef/resources.rb +12 -1
  51. data/lib/chef/secret_fetcher.rb +54 -0
  52. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +53 -0
  53. data/lib/chef/secret_fetcher/azure_key_vault.rb +56 -0
  54. data/lib/chef/secret_fetcher/base.rb +72 -0
  55. data/lib/chef/secret_fetcher/example.rb +46 -0
  56. data/lib/chef/version.rb +1 -1
  57. data/spec/functional/mixin/from_file_spec.rb +1 -1
  58. data/spec/integration/recipes/recipe_dsl_spec.rb +1 -1
  59. data/spec/integration/recipes/resource_action_spec.rb +4 -4
  60. data/spec/support/shared/unit/provider/file.rb +2 -8
  61. data/spec/unit/data_bag_item_spec.rb +2 -2
  62. data/spec/unit/data_bag_spec.rb +1 -1
  63. data/spec/unit/dsl/render_helpers_spec.rb +102 -0
  64. data/spec/unit/dsl/secret_spec.rb +65 -0
  65. data/spec/unit/policy_builder/dynamic_spec.rb +0 -5
  66. data/spec/unit/policy_builder/policyfile_spec.rb +144 -56
  67. data/spec/unit/provider/apt_update_spec.rb +3 -1
  68. data/spec/unit/provider/mount/aix_spec.rb +1 -1
  69. data/spec/unit/provider/package/powershell_spec.rb +74 -12
  70. data/spec/unit/resource/windows_defender_exclusion_spec.rb +62 -0
  71. data/spec/unit/resource/windows_defender_spec.rb +71 -0
  72. data/spec/unit/resource/windows_update_settings_spec.rb +64 -0
  73. data/spec/unit/secret_fetcher/azure_key_vault_spec.rb +63 -0
  74. data/spec/unit/secret_fetcher_spec.rb +82 -0
  75. metadata +51 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3259221c96da998dc7da695df0488bcfbe781ce3764dcd98309c78c1a46cb56c
4
- data.tar.gz: 120938b331b2e96306b91c5a192a73ebbfaeebce9b3febfccae32d7e7918e4a6
3
+ metadata.gz: 45a45627ed2995c171f44e97e524e17cdcc2b8a3c4566c6cba3e7e57a5810f71
4
+ data.tar.gz: 5bbe7e7fecc35ddfddc730addb9a944a798ff252a239e433f6894228c9af6359
5
5
  SHA512:
6
- metadata.gz: f1191c217a427591d0cdd0b0223249ed83164f53da4edd463258dfe37d084b9e928627eb9020a20aeb87f141d160eb72b64d4c1d37e47b7206f50e120b7738fe
7
- data.tar.gz: '0148bdae1adf6ffa4539aab3c8dbc47fc225cb5d6f1e421967be4d53ce7504f9ff10af21cd0410412847b9e99d6308892b32a0ab673bd657ccb6922f191c91a1'
6
+ metadata.gz: 3ef336ebe43aa213491af9e263758101f040ee306537d8d3d0db4a6484fa33daf78c0a524525ee648688cfe9fa2c77d5163ce310d6977b85c0ccf761fcc763ba
7
+ data.tar.gz: 554e9acfa53f9bc83a3b04cd9efb913b984bf9f69cb58b924a3ad9744fd2af8ff8bf42b6b495ba243ad71364d59ba433f6c440b9768c59aa3a7d9239948e2c7e
data/Gemfile CHANGED
@@ -22,13 +22,14 @@ group(:omnibus_package) do
22
22
  gem "rb-readline"
23
23
  gem "inspec-core-bin", "~> 4.24" # need to provide the binaries for inspec
24
24
  gem "chef-vault"
25
- gem "ed25519", "~> 1.2" # to make it possible to install knife into chef. Remove this in Chef 18
26
25
  end
27
26
 
28
27
  group(:omnibus_package, :pry) do
29
- gem "pry"
28
+ # Locked because pry-byebug is broken with 13+.
29
+ # some work is ongoing? https://github.com/deivid-rodriguez/pry-byebug/issues/343
30
+ gem "pry", "= 0.13.0"
30
31
  # byebug does not install on freebsd on ruby 3.0
31
- # gem "pry-byebug"
32
+ gem "pry-byebug" unless RUBY_PLATFORM =~ /freebsd/i
32
33
  gem "pry-stack_explorer"
33
34
  end
34
35
 
data/chef.gemspec CHANGED
@@ -55,6 +55,7 @@ Gem::Specification.new do |s|
55
55
 
56
56
  s.add_dependency "proxifier", "~> 1.0"
57
57
 
58
+ s.add_dependency "aws-sdk-secretsmanager", "~> 1.46"
58
59
  s.bindir = "bin"
59
60
  s.executables = %w{ }
60
61
 
data/lib/chef/client.rb CHANGED
@@ -751,7 +751,7 @@ class Chef
751
751
  end
752
752
 
753
753
  # Notification registration
754
- class<<self
754
+ class << self
755
755
  #
756
756
  # Add a listener for the 'client run started' event.
757
757
  #
data/lib/chef/data_bag.rb CHANGED
@@ -32,8 +32,7 @@ class Chef
32
32
  include Chef::Mixin::FromFile
33
33
  include Chef::Mixin::ParamsValidate
34
34
 
35
- # Regex reference: https://rubular.com/r/oIMySIO4USPm5x
36
- VALID_NAME = /^[\-[:alnum:]_]+$/.freeze
35
+ VALID_NAME = /^[\.\-[:alnum:]_]+$/.freeze
37
36
  RESERVED_NAMES = /^(node|role|environment|client)$/.freeze
38
37
 
39
38
  def self.validate_name!(name)
@@ -36,8 +36,7 @@ class Chef
36
36
  include Chef::Mixin::FromFile
37
37
  include Chef::Mixin::ParamsValidate
38
38
 
39
- # Regex reference: https://rubular.com/r/oIMySIO4USPm5x
40
- VALID_ID = /^[\-[:alnum:]_]+$/.freeze
39
+ VALID_ID = /^[\.\-[:alnum:]_]+$/.freeze
41
40
 
42
41
  def self.validate_id!(id_str)
43
42
  if id_str.nil? || ( id_str !~ VALID_ID )
@@ -79,10 +79,12 @@ class Chef
79
79
  return true if location =~ /^(.*?):(\d+):in/ && begin
80
80
  # Don't buffer the whole file in memory, so read it one line at a time.
81
81
  line_no = $2.to_i
82
- location_file = ::File.open($1)
83
- (line_no - 1).times { location_file.readline } # Read all the lines we don't care about.
84
- relevant_line = location_file.readline
85
- relevant_line.match?(/#.*chef:silence_deprecation($|[^:]|:#{self.class.deprecation_key})/)
82
+ if File.exist?($1) # some stacktraces come from `eval` and not a file
83
+ location_file = ::File.open($1)
84
+ (line_no - 1).times { location_file.readline } # Read all the lines we don't care about.
85
+ relevant_line = location_file.readline
86
+ relevant_line.match?(/#.*chef:silence_deprecation($|[^:]|:#{self.class.deprecation_key})/)
87
+ end
86
88
  end
87
89
 
88
90
  false
@@ -257,6 +259,10 @@ class Chef
257
259
  target 34
258
260
  end
259
261
 
262
+ class PolicyfileCompatMode < Base
263
+ target 35
264
+ end
265
+
260
266
  class Generic < Base
261
267
  def url
262
268
  "https://docs.chef.io/chef_deprecations_client/"
data/lib/chef/dsl.rb CHANGED
@@ -4,3 +4,4 @@ require_relative "dsl/data_query"
4
4
  require_relative "dsl/include_recipe"
5
5
  require_relative "dsl/include_attribute"
6
6
  require_relative "dsl/registry_helper"
7
+ require_relative "dsl/secret"
@@ -0,0 +1,44 @@
1
+ #
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require_relative "toml"
17
+ require_relative "../json_compat"
18
+ autoload :YAML, "yaml"
19
+
20
+ class Chef
21
+ module DSL
22
+ module RenderHelpers
23
+
24
+ # pretty-print a hash as a JSON string
25
+ def render_json(hash)
26
+ JSON.pretty_generate(hash) + "\n"
27
+ end
28
+
29
+ # pretty-print a hash as a TOML string
30
+ def render_toml(hash)
31
+ Chef::DSL::Toml::Dumper.new(hash).toml_str
32
+ end
33
+
34
+ # pretty-print a hash as a YAML string
35
+ def render_yaml(hash)
36
+ yaml_content = hash.transform_keys(&:to_s).to_yaml
37
+ # above replaces first-level keys with strings, below the rest
38
+ yaml_content.gsub!(" :", " ")
39
+ end
40
+
41
+ extend self
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,64 @@
1
+ #
2
+ # Author:: Marc Paradise (<marc@chef.io>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require_relative "../secret_fetcher"
19
+
20
+ class Chef
21
+ module DSL
22
+ module Secret
23
+
24
+ # Helper method which looks up a secret using the given service and configuration,
25
+ # and returns the retrieved secret value.
26
+ # This DSL providers a wrapper around [Chef::SecretFetcher]
27
+ #
28
+ # Use of the secret helper in the context of a resource block will automatically mark
29
+ # that resource as 'sensitive', preventing resource data from being logged. See [Chef::Resource#sensitive].
30
+ #
31
+ # @option name [Object] The identifier or name for this secret
32
+ # @option version [Object] The secret version. If a service supports versions
33
+ # and no version is provided, the latest version will be fetched.
34
+ # @option service [Symbol] The service identifier for the service that will
35
+ # perform the secret lookup. See
36
+ # [Chef::SecretFetcher::SECRET_FETCHERS]
37
+ # @option config [Hash] The configuration that the named service expects
38
+ #
39
+ # @return result [Object] The response object type is determined by the fetcher but will usually be a string or a hash.
40
+ # See individual fetcher documentation to know what to expect for a given service.
41
+ #
42
+ # @example
43
+ #
44
+ # This example uses the built-in :example secret manager service, which
45
+ # accepts a hash of secrets.
46
+ #
47
+ # value = secret(name: "test1", service: :example, config: { "test1" => "value1" })
48
+ # log "My secret is #{value}"
49
+ #
50
+ # value = secret(name: "test1", service: :aws_secrets_manager, version: "v1", config: { region: "us-west-1" })
51
+ # log "My secret is #{value}"
52
+ def secret(name: nil, version: nil, service: nil, config: nil)
53
+ Chef::Log.warn <<~EOM.gsub("\n", "")
54
+ The secrets Chef Infra language helper is currently in beta.
55
+ This helper will most likely change over time in potentially breaking ways.
56
+ If you have feedback or you'd like to be part of the future design of this
57
+ helper e-mail us at secrets_management_beta@progress.com"
58
+ EOM
59
+ sensitive(true) if is_a?(Chef::Resource)
60
+ Chef::SecretFetcher.for_service(service, config).fetch(name, version)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,116 @@
1
+ require "date"
2
+
3
+ # imported from https://github.com/chef-cookbooks/habitat
4
+ class Chef
5
+ module DSL
6
+ module Toml
7
+ class Dumper
8
+ attr_reader :toml_str
9
+
10
+ def initialize(hash)
11
+ @toml_str = ""
12
+
13
+ visit(hash, [])
14
+ end
15
+
16
+ private
17
+
18
+ def visit(hash, prefix, extra_brackets = false)
19
+ simple_pairs, nested_pairs, table_array_pairs = sort_pairs hash
20
+
21
+ if prefix.any? && (simple_pairs.any? || hash.empty?)
22
+ print_prefix prefix, extra_brackets
23
+ end
24
+
25
+ dump_pairs simple_pairs, nested_pairs, table_array_pairs, prefix
26
+ end
27
+
28
+ def sort_pairs(hash)
29
+ nested_pairs = []
30
+ simple_pairs = []
31
+ table_array_pairs = []
32
+
33
+ hash.keys.sort.each do |key|
34
+ val = hash[key]
35
+ element = [key, val]
36
+
37
+ if val.is_a? Hash
38
+ nested_pairs << element
39
+ elsif val.is_a?(Array) && val.first.is_a?(Hash)
40
+ table_array_pairs << element
41
+ else
42
+ simple_pairs << element
43
+ end
44
+ end
45
+
46
+ [simple_pairs, nested_pairs, table_array_pairs]
47
+ end
48
+
49
+ def dump_pairs(simple, nested, table_array, prefix = [])
50
+ # First add simple pairs, under the prefix
51
+ dump_simple_pairs simple
52
+ dump_nested_pairs nested, prefix
53
+ dump_table_array_pairs table_array, prefix
54
+ end
55
+
56
+ def dump_simple_pairs(simple_pairs)
57
+ simple_pairs.each do |key, val|
58
+ key = quote_key(key) unless bare_key? key
59
+ @toml_str << "#{key} = #{to_toml(val)}\n"
60
+ end
61
+ end
62
+
63
+ def dump_nested_pairs(nested_pairs, prefix)
64
+ nested_pairs.each do |key, val|
65
+ key = quote_key(key) unless bare_key? key
66
+
67
+ visit val, prefix + [key], false
68
+ end
69
+ end
70
+
71
+ def dump_table_array_pairs(table_array_pairs, prefix)
72
+ table_array_pairs.each do |key, val|
73
+ key = quote_key(key) unless bare_key? key
74
+ aux_prefix = prefix + [key]
75
+
76
+ val.each do |child|
77
+ print_prefix aux_prefix, true
78
+ args = sort_pairs(child) << aux_prefix
79
+
80
+ dump_pairs(*args)
81
+ end
82
+ end
83
+ end
84
+
85
+ def print_prefix(prefix, array = false)
86
+ new_prefix = prefix.join(".")
87
+ new_prefix = "[#{new_prefix}]" if array
88
+
89
+ @toml_str += "[#{new_prefix}]\n"
90
+ end
91
+
92
+ def to_toml(obj)
93
+ if obj.is_a?(Time) || obj.is_a?(DateTime)
94
+ obj.strftime("%Y-%m-%dT%H:%M:%SZ")
95
+ elsif obj.is_a?(Date)
96
+ obj.strftime("%Y-%m-%d")
97
+ elsif obj.is_a? Regexp
98
+ obj.inspect.inspect
99
+ elsif obj.is_a? String
100
+ obj.inspect.gsub(/\\(#[$@{])/, '\1')
101
+ else
102
+ obj.inspect
103
+ end
104
+ end
105
+
106
+ def bare_key?(key)
107
+ !!key.to_s.match(/^[a-zA-Z0-9_-]*$/)
108
+ end
109
+
110
+ def quote_key(key)
111
+ '"' + key.gsub('"', '\\"') + '"'
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -22,6 +22,9 @@ require_relative "data_query"
22
22
  require_relative "chef_vault"
23
23
  require_relative "registry_helper"
24
24
  require_relative "powershell"
25
+ require_relative "secret"
26
+ require_relative "render_helpers"
27
+ require_relative "toml"
25
28
  require_relative "../mixin/powershell_exec"
26
29
  require_relative "../mixin/powershell_out"
27
30
  require_relative "../mixin/shell_out"
@@ -47,6 +50,8 @@ class Chef
47
50
  include Chef::DSL::ChefVault
48
51
  include Chef::DSL::RegistryHelper
49
52
  include Chef::DSL::Powershell
53
+ include Chef::DSL::RenderHelpers
54
+ include Chef::DSL::Secret
50
55
  include Chef::Mixin::PowershellExec
51
56
  include Chef::Mixin::PowershellOut
52
57
  include Chef::Mixin::ShellOut
@@ -290,6 +290,28 @@ class Chef
290
290
 
291
291
  end
292
292
 
293
+ class Secret
294
+ class RetrievalError < RuntimeError; end
295
+ class ConfigurationInvalid < RuntimeError; end
296
+ class FetchFailed < RuntimeError; end
297
+ class MissingSecretName < RuntimeError; end
298
+ class InvalidSecretName < RuntimeError; end
299
+
300
+ class InvalidFetcherService < RuntimeError
301
+ def initialize(given, fetcher_service_names)
302
+ super("#{given} is not a supported secrets service. Supported services are: :#{fetcher_service_names.join(" :")}")
303
+ end
304
+ end
305
+
306
+ class MissingFetcher < RuntimeError
307
+ def initialize(fetcher_service_names)
308
+ super("No secret service provided. Supported services are: :#{fetcher_service_names.join(" :")}")
309
+ end
310
+ end
311
+
312
+ class MissingVaultName < RuntimeError; end
313
+ end
314
+
293
315
  # Exception class for collecting multiple failures. Used when running
294
316
  # delayed notifications so that chef can process each delayed
295
317
  # notification even if chef client or other notifications fail.
@@ -59,7 +59,7 @@ class Chef
59
59
 
60
60
  def stripped_source_line(resource)
61
61
  # strip the leading path off of the source line
62
- resource.source_line.gsub(%r{.*/cookbooks/}, "").gsub(%r{.*/chef-[0-9\.]+/}, "")
62
+ resource.source_line&.gsub(%r{.*/cookbooks/}, "")&.gsub(%r{.*/chef-[0-9\.]+/}, "")
63
63
  end
64
64
  end
65
65
  end
@@ -25,7 +25,7 @@ require "json" unless defined?(JSON)
25
25
  class Chef
26
26
  class JSONCompat
27
27
 
28
- class <<self
28
+ class << self
29
29
 
30
30
  def parse(source, opts = {})
31
31
  FFI_Yajl::Parser.parse(source, opts)
@@ -32,14 +32,8 @@ class Chef
32
32
  # Policyfile is a policy builder implementation that gets run
33
33
  # list and cookbook version information from a single document.
34
34
  #
35
- # == Unsupported Options:
36
- # * override_runlist:: This could potentially be integrated into the
37
- # policyfile, or replaced with a similar feature that has different
38
- # semantics.
39
- # * specific_recipes:: put more design thought into this use case.
40
- # * run_list in json_attribs:: would be ignored anyway, so it raises an error.
41
- # * chef-solo:: not currently supported. Need more design thought around
42
- # how this should work.
35
+ # Does not support legacy chef-solo or roles/environments.
36
+ #
43
37
  class Policyfile
44
38
 
45
39
  class UnsupportedFeature < StandardError; end
@@ -81,10 +75,12 @@ class Chef
81
75
  attr_reader :ohai_data
82
76
  attr_reader :json_attribs
83
77
  attr_reader :run_context
78
+ attr_reader :override_runlist
84
79
 
85
80
  def initialize(node_name, ohai_data, json_attribs, override_runlist, events)
86
81
  @node_name = node_name
87
82
  @ohai_data = ohai_data
83
+ @override_runlist = override_runlist
88
84
  @json_attribs = json_attribs
89
85
  @events = events
90
86
 
@@ -94,32 +90,11 @@ class Chef
94
90
  raise UnsupportedFeature, "Policyfile does not support chef-solo. Use #{ChefUtils::Dist::Infra::CLIENT} local mode instead."
95
91
  end
96
92
 
97
- if override_runlist
98
- raise UnsupportedFeature, "Policyfile does not support override run lists. Use named run_lists instead."
99
- end
100
-
101
- if json_attribs && json_attribs.key?("run_list")
102
- raise UnsupportedFeature, "Policyfile does not support setting the run_list in json data."
103
- end
104
-
105
93
  if Chef::Config[:environment] && !Chef::Config[:environment].chomp.empty?
106
94
  raise UnsupportedFeature, "Policyfile does not work with an Environment configured."
107
95
  end
108
96
  end
109
97
 
110
- ## API Compat ##
111
- # Methods related to unsupported features
112
-
113
- # Override run_list is not supported.
114
- def original_runlist
115
- nil
116
- end
117
-
118
- # Override run_list is not supported.
119
- def override_runlist
120
- nil
121
- end
122
-
123
98
  # Policyfile gives you the run_list already expanded, but users of this
124
99
  # class may expect to get a run_list expansion compatible object by
125
100
  # calling this method.
@@ -148,17 +123,27 @@ class Chef
148
123
  # consume_external_attrs may add items to the run_list. Save the
149
124
  # expanded run_list, which we will pass to the server later to
150
125
  # determine which versions of cookbooks to use.
126
+
127
+ unless Chef::Config[:policy_document_native_api]
128
+ Chef.deprecated(:policyfile_compat_mode, "The chef-server 11 policyfile compat mode is deprecated, please set policy_document_native_api to true in your config")
129
+ end
130
+
151
131
  node.reset_defaults_and_overrides
152
132
 
153
133
  node.consume_external_attrs(ohai_data, json_attribs)
154
134
 
135
+ setup_run_list_override
136
+
155
137
  expand_run_list
156
138
  apply_policyfile_attributes
157
139
 
140
+ if persistent_run_list_set?
141
+ Chef::Log.warn("The node.run_list setting is overriding the Policyfile run_list")
142
+ end
158
143
  Chef::Log.info("Run List is [#{run_list}]")
159
- Chef::Log.info("Run List expands to [#{run_list_with_versions_for_display.join(", ")}]")
144
+ Chef::Log.info("Run List expands to [#{run_list_with_versions_for_display(run_list).join(", ")}]")
160
145
 
161
- events.node_load_completed(node, run_list_with_versions_for_display, Chef::Config)
146
+ events.node_load_completed(node, run_list_with_versions_for_display(run_list), Chef::Config)
162
147
  events.run_list_expanded(run_list_expansion_ish)
163
148
 
164
149
  # we must do this after `node.consume_external_attrs`
@@ -194,6 +179,11 @@ class Chef
194
179
  events.cookbook_compilation_start(run_context)
195
180
 
196
181
  run_context.load(run_list_expansion_ish)
182
+ if specific_recipes
183
+ specific_recipes.each do |recipe_file|
184
+ run_context.load_recipe_file(recipe_file)
185
+ end
186
+ end
197
187
 
198
188
  events.cookbook_compilation_complete(run_context)
199
189
 
@@ -206,7 +196,7 @@ class Chef
206
196
  #
207
197
  # @return [RunListExpansionIsh] A RunListExpansion duck-type.
208
198
  def expand_run_list
209
- CookbookCacheCleaner.instance.skip_removal = true if named_run_list_requested?
199
+ validate_run_list!(run_list)
210
200
 
211
201
  node.run_list(run_list)
212
202
  node.automatic_attrs[:policy_revision] = revision_id
@@ -231,21 +221,25 @@ class Chef
231
221
  cookbooks_to_sync
232
222
  end
233
223
 
234
- # Whether or not this is a temporary policy. Since PolicyBuilder doesn't
235
- # support override_runlist, this is always false.
224
+ ## Internal Public API ##
225
+
226
+ # @api private
236
227
  #
237
- # @return [false]
238
- def temporary_policy?
239
- false
228
+ # Validate run_list against policyfile cookbooks
229
+ #
230
+ def validate_run_list!(run_list)
231
+ run_list.map do |recipe_spec|
232
+ cookbook, recipe = parse_recipe_spec(recipe_spec)
233
+ lock_data = cookbook_lock_for(cookbook)
234
+ raise PolicyfileError, "invalid run_list item '#{recipe_spec}' not in cookbook set of PolicyFile #{policyfile_location}" unless lock_data
235
+ end
240
236
  end
241
237
 
242
- ## Internal Public API ##
243
-
244
238
  # @api private
245
239
  #
246
240
  # Generates an array of strings with recipe names including version and
247
241
  # identifier info.
248
- def run_list_with_versions_for_display
242
+ def run_list_with_versions_for_display(run_list)
249
243
  run_list.map do |recipe_spec|
250
244
  cookbook, recipe = parse_recipe_spec(recipe_spec)
251
245
  lock_data = cookbook_lock_for(cookbook)
@@ -287,9 +281,14 @@ class Chef
287
281
 
288
282
  # @api private
289
283
  def parse_recipe_spec(recipe_spec)
290
- rmatch = recipe_spec.match(/recipe\[([^:]+)::([^:]+)\]/)
284
+ rmatch = recipe_spec.to_s.match(/recipe\[([^:]+)::([^:]+)\]/)
291
285
  if rmatch.nil?
292
- raise PolicyfileError, "invalid recipe specification #{recipe_spec} in Policyfile from #{policyfile_location}"
286
+ rmatch = recipe_spec.to_s.match(/recipe\[([^:]+)\]/)
287
+ if rmatch.nil?
288
+ raise PolicyfileError, "invalid recipe specification #{recipe_spec} in Policyfile from #{policyfile_location}"
289
+ else
290
+ [rmatch[1], "default"]
291
+ end
293
292
  else
294
293
  [rmatch[1], rmatch[2]]
295
294
  end
@@ -301,8 +300,15 @@ class Chef
301
300
  end
302
301
 
303
302
  # @api private
303
+ # @return [Array<String>]
304
304
  def run_list
305
- if named_run_list_requested?
305
+ return override_runlist.map(&:to_s) if override_runlist
306
+
307
+ if json_attribs["run_list"]
308
+ json_attribs["run_list"]
309
+ elsif persistent_run_list_set?
310
+ node.run_list
311
+ elsif named_run_list_requested?
306
312
  named_run_list || raise(ConfigurationError,
307
313
  "Policy '#{retrieved_policy_name}' revision '#{revision_id}' does not have named_run_list '#{named_run_list_name}'" +
308
314
  "(available named_run_lists: [#{available_named_run_lists.join(", ")}])")
@@ -458,7 +464,7 @@ class Chef
458
464
  # should be reduced to a single call.
459
465
  def cookbooks_to_sync
460
466
  @cookbook_to_sync ||= begin
461
- events.cookbook_resolution_start(run_list_with_versions_for_display)
467
+ events.cookbook_resolution_start(run_list_with_versions_for_display(run_list))
462
468
 
463
469
  cookbook_versions_by_name = cookbook_locks.inject({}) do |cb_map, (name, lock_data)|
464
470
  cb_map[name] = manifest_for(name, lock_data)
@@ -470,7 +476,7 @@ class Chef
470
476
  end
471
477
  rescue Exception => e
472
478
  # TODO: wrap/munge exception to provide helpful error output
473
- events.cookbook_resolution_failed(run_list_with_versions_for_display, e)
479
+ events.cookbook_resolution_failed(run_list_with_versions_for_display(run_list), e)
474
480
  raise
475
481
  end
476
482
 
@@ -509,6 +515,13 @@ class Chef
509
515
  Chef::Config
510
516
  end
511
517
 
518
+ # Indicates whether the policy is temporary, which means an
519
+ # override_runlist was provided. Chef::Client uses this to decide whether
520
+ # to do the final node save at the end of the run or not.
521
+ def temporary_policy?
522
+ node.override_runlist_set?
523
+ end
524
+
512
525
  private
513
526
 
514
527
  # This method injects the run_context and into the Chef class.
@@ -533,6 +546,10 @@ class Chef
533
546
  (policy["named_run_lists"] || {}).keys
534
547
  end
535
548
 
549
+ def persistent_run_list_set?
550
+ Chef::Config[:policy_persist_run_list] && node.run_list && !node.run_list.empty?
551
+ end
552
+
536
553
  def named_run_list_requested?
537
554
  !!Chef::Config[:named_run_list]
538
555
  end
@@ -567,6 +584,32 @@ class Chef
567
584
  Chef::CookbookVersion.from_cb_artifact_data(raw_manifest)
568
585
  end
569
586
 
587
+ def setup_run_list_override
588
+ unless override_runlist.nil?
589
+ runlist_override_sanity_check!
590
+ node.override_runlist = override_runlist
591
+ Chef::Log.warn "Run List override has been provided."
592
+ Chef::Log.warn "Original Run List: [#{node.primary_runlist}]"
593
+ Chef::Log.warn "Overridden Run List: [#{node.run_list}]"
594
+ end
595
+ end
596
+
597
+ # Ensures runlist override contains RunListItem instances
598
+ def runlist_override_sanity_check!
599
+ # Convert to array and remove whitespace
600
+ if override_runlist.is_a?(String)
601
+ @override_runlist = override_runlist.split(",").map(&:strip)
602
+ end
603
+ @override_runlist = [override_runlist].flatten.compact
604
+ override_runlist.map! do |item|
605
+ if item.is_a?(Chef::RunList::RunListItem)
606
+ item
607
+ else
608
+ Chef::RunList::RunListItem.new(item)
609
+ end
610
+ end
611
+ end
612
+
570
613
  end
571
614
  end
572
615
  end