chef 17.3.48 → 17.4.25

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef/application.rb +3 -1
  3. data/lib/chef/compliance/default_attributes.rb +5 -3
  4. data/lib/chef/compliance/runner.rb +15 -1
  5. data/lib/chef/dsl/secret.rb +3 -3
  6. data/lib/chef/exceptions.rb +0 -2
  7. data/lib/chef/formatters/error_mapper.rb +2 -2
  8. data/lib/chef/provider/execute.rb +1 -1
  9. data/lib/chef/provider/group/dscl.rb +1 -1
  10. data/lib/chef/provider/launchd.rb +6 -6
  11. data/lib/chef/provider/subversion.rb +4 -4
  12. data/lib/chef/provider/support/yum_repo.erb +1 -1
  13. data/lib/chef/provider/systemd_unit.rb +17 -16
  14. data/lib/chef/provider/user/mac.rb +3 -3
  15. data/lib/chef/provider/yum_repository.rb +27 -43
  16. data/lib/chef/provider/zypper_repository.rb +3 -3
  17. data/lib/chef/provider.rb +26 -1
  18. data/lib/chef/provider_resolver.rb +8 -2
  19. data/lib/chef/resource/homebrew_cask.rb +1 -1
  20. data/lib/chef/resource/inspec_waiver_file_entry.rb +2 -2
  21. data/lib/chef/resource/launchd.rb +3 -3
  22. data/lib/chef/resource/remote_file.rb +1 -1
  23. data/lib/chef/resource/rhsm_subscription.rb +5 -5
  24. data/lib/chef/resource/ruby_block.rb +100 -0
  25. data/lib/chef/resource/scm/subversion.rb +1 -1
  26. data/lib/chef/resource/sysctl.rb +2 -2
  27. data/lib/chef/resource/systemd_unit.rb +3 -3
  28. data/lib/chef/resource/yum_package.rb +1 -5
  29. data/lib/chef/resource.rb +14 -18
  30. data/lib/chef/resource_inspector.rb +6 -2
  31. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +16 -4
  32. data/lib/chef/secret_fetcher/azure_key_vault.rb +31 -9
  33. data/lib/chef/secret_fetcher/base.rb +5 -1
  34. data/lib/chef/secret_fetcher.rb +5 -4
  35. data/lib/chef/version.rb +1 -1
  36. data/spec/integration/compliance/compliance_spec.rb +1 -0
  37. data/spec/integration/recipes/resource_action_spec.rb +2 -2
  38. data/spec/unit/compliance/runner_spec.rb +46 -2
  39. data/spec/unit/dsl/secret_spec.rb +8 -2
  40. data/spec/unit/provider_spec.rb +23 -0
  41. data/spec/unit/resource/homebrew_cask_spec.rb +29 -11
  42. data/spec/unit/resource/rhsm_subscription_spec.rb +50 -3
  43. data/spec/unit/resource/systemd_unit_spec.rb +1 -1
  44. data/spec/unit/resource_spec.rb +19 -8
  45. data/spec/unit/secret_fetcher/aws_secrets_manager_spec.rb +70 -0
  46. data/spec/unit/secret_fetcher/azure_key_vault_spec.rb +23 -16
  47. data/spec/unit/secret_fetcher_spec.rb +9 -9
  48. metadata +7 -6
@@ -29,7 +29,7 @@ class Chef
29
29
 
30
30
  def load_current_resource; end
31
31
 
32
- action :create do
32
+ action :create, description: "Add a new Zypper repository." do
33
33
  if new_resource.gpgautoimportkeys
34
34
  install_gpg_keys(new_resource.gpgkey)
35
35
  else
@@ -50,13 +50,13 @@ class Chef
50
50
  end
51
51
  end
52
52
 
53
- action :delete do
53
+ action :delete, description: "Remove a Zypper repository." do
54
54
  execute "zypper --quiet --non-interactive removerepo #{escaped_repo_name}" do
55
55
  only_if "zypper --quiet lr #{escaped_repo_name}"
56
56
  end
57
57
  end
58
58
 
59
- action :refresh do
59
+ action :refresh, description: "Refresh Zypper repository." do
60
60
  execute "zypper --quiet --non-interactive refresh --force #{escaped_repo_name}" do
61
61
  only_if "zypper --quiet lr #{escaped_repo_name}"
62
62
  end
data/lib/chef/provider.rb CHANGED
@@ -57,10 +57,12 @@ class Chef
57
57
  #
58
58
  # @since 13.0
59
59
  # @param name [String, Symbol] Name of the action to define.
60
+ # @param description [String] description of the action
60
61
  # @param block [Proc] Body of the action.
61
62
  #
62
63
  # @return [void]
63
- def self.action(name, &block)
64
+ def self.action(name, description: nil, &block)
65
+ action_descriptions[name.to_sym] = description unless description.nil?
64
66
  # We need the block directly in a method so that `return` works.
65
67
  define_method("compile_action_#{name}", &block)
66
68
  class_eval <<-EOM
@@ -70,6 +72,29 @@ class Chef
70
72
  EOM
71
73
  end
72
74
 
75
+ # Return the hash of action descriptions defined for
76
+ # the provider class.
77
+ #
78
+ # @return [Hash] hash of [Symbol] => [String] containing
79
+ # any provided action descriptions.
80
+ def self.action_descriptions
81
+ @action_descriptions ||= {}
82
+ end
83
+
84
+ # Retrieve the description for a provider's action, if
85
+ # any description has been included in the definition.
86
+ #
87
+ # @param action [Symbol,String] the action name
88
+ # @return [String] the description of the action provided, or nil if no description
89
+ # was defined
90
+ def self.action_description(action)
91
+ description = action_descriptions[action.to_sym]
92
+ if description.nil? && superclass.respond_to?(:action_description)
93
+ description = superclass.action_description(action)
94
+ end
95
+ description
96
+ end
97
+
73
98
  # Deprecation stub for the old use_inline_resources mode.
74
99
  #
75
100
  # @return [void]
@@ -57,10 +57,16 @@ class Chef
57
57
  end
58
58
 
59
59
  def resolve
60
- maybe_explicit_provider(resource) ||
60
+ resolved = maybe_explicit_provider(resource) ||
61
61
  maybe_custom_resource(resource) ||
62
- maybe_dynamic_provider_resolution(resource, action) ||
62
+ maybe_dynamic_provider_resolution(resource, action)
63
+
64
+ if resolved.nil?
65
+ raise(Chef::Exceptions::ProviderNotFound, "Cannot find a provider for #{resource}") if node.nil?
66
+
63
67
  raise(Chef::Exceptions::ProviderNotFound, "Cannot find a provider for #{resource} on #{node["platform"]} version #{node["platform_version"]}")
68
+ end
69
+ resolved
64
70
  end
65
71
 
66
72
  # Does NOT call provides? on the resource (it is assumed this is being
@@ -34,7 +34,7 @@ class Chef
34
34
 
35
35
  property :cask_name, String,
36
36
  description: "An optional property to set the cask name if it differs from the resource block's name.",
37
- regex: %r{^[\w/-]+$},
37
+ regex: %r{^[\w/\-@]+$},
38
38
  validation_message: "The provided Homebrew cask name is not valid. Cask names can contain alphanumeric characters, _, -, or / only!",
39
39
  name_property: true
40
40
 
@@ -84,13 +84,13 @@ class Chef
84
84
  }
85
85
 
86
86
  property :run_test, [true, false],
87
- description: "If present and true, the control will run and be reported, but failures in it won’t make the overall run fail. If absent or false, the control will not be run."
87
+ description: "If present and `true`, the control will run and be reported, but failures in it won’t make the overall run fail. If absent or `false`, the control will not be run."
88
88
 
89
89
  property :justification, String,
90
90
  description: "Can be any text you want and might include a reason for the waiver as well as who signed off on the waiver."
91
91
 
92
92
  property :backup, [false, Integer],
93
- description: "The number of backups to be kept in /var/chef/backup (for UNIX- and Linux-based platforms) or C:/chef/backup (for the Microsoft Windows platform). Set to false to prevent backups from being kept.",
93
+ description: "The number of backups to be kept in `/var/chef/backup` (for UNIX- and Linux-based platforms) or `C:/chef/backup` (for the Microsoft Windows platform). Set to `false` to prevent backups from being kept.",
94
94
  default: false
95
95
 
96
96
  action :add do
@@ -36,7 +36,7 @@ class Chef
36
36
 
37
37
  property :backup, [Integer, FalseClass],
38
38
  desired_state: false,
39
- description: "The number of backups to be kept in /var/chef/backup. Set to false to prevent backups from being kept."
39
+ description: "The number of backups to be kept in `/var/chef/backup`. Set to `false` to prevent backups from being kept."
40
40
 
41
41
  property :cookbook, String,
42
42
  desired_state: false,
@@ -197,10 +197,10 @@ class Chef
197
197
  description: "The intended purpose of the job: `Adaptive`, `Background`, `Interactive`, or `Standard`."
198
198
 
199
199
  property :program, String,
200
- description: "The first argument of execvp, typically the file name associated with the file to be executed. This value must be specified if program_arguments is not specified, and vice-versa."
200
+ description: "The first argument of `execvp`, typically the file name associated with the file to be executed. This value must be specified if `program_arguments` is not specified, and vice-versa."
201
201
 
202
202
  property :program_arguments, Array,
203
- description: "The second argument of execvp. If program is not specified, this property must be specified and will be handled as if it were the first argument."
203
+ description: "The second argument of `execvp`. If program is not specified, this property must be specified and will be handled as if it were the first argument."
204
204
 
205
205
  property :queue_directories, Array,
206
206
  description: "An array of non-empty directories which, if any are modified, will cause a job to be started."
@@ -85,7 +85,7 @@ class Chef
85
85
  end
86
86
 
87
87
  property :use_etag, [ TrueClass, FalseClass ], default: true,
88
- description: "Enable ETag headers. Set to false to disable ETag headers. To use this setting, `use_conditional_get` must also be set to true."
88
+ description: "Enable ETag headers. Set to `false` to disable ETag headers. To use this setting, `use_conditional_get` must also be set to true."
89
89
 
90
90
  alias :use_etags :use_etag
91
91
 
@@ -32,11 +32,11 @@ class Chef
32
32
  name_property: true
33
33
 
34
34
  action :attach, description: "Attach the node to a subscription pool." do
35
- execute "Attach subscription pool #{new_resource.pool_id}" do
36
- command "subscription-manager attach --pool=#{new_resource.pool_id}"
37
- default_env true
38
- action :run
39
- not_if { subscription_attached?(new_resource.pool_id) }
35
+ unless subscription_attached?(new_resource.pool_id)
36
+ converge_by("attach subscription pool #{new_resource.pool_id}") do
37
+ shell_out!("subscription-manager attach --pool=#{new_resource.pool_id}")
38
+ build_resource(:package, "rhsm_subscription-#{new_resource.pool_id}-flush_cache").run_action(:flush_cache)
39
+ end
40
40
  end
41
41
  end
42
42
 
@@ -29,6 +29,106 @@ class Chef
29
29
  provides :ruby_block, target_mode: true
30
30
 
31
31
  description "Use the **ruby_block** resource to execute Ruby code during a #{ChefUtils::Dist::Infra::PRODUCT} run. Ruby code in the `ruby_block` resource is evaluated with other resources during convergence, whereas Ruby code outside of a `ruby_block` resource is evaluated before other resources, as the recipe is compiled."
32
+ examples <<~'DOC'
33
+ **Reload Chef Infra Client configuration data**
34
+
35
+ ```ruby
36
+ ruby_block 'reload_client_config' do
37
+ block do
38
+ Chef::Config.from_file('/etc/chef/client.rb')
39
+ end
40
+ action :run
41
+ end
42
+ ```
43
+
44
+ **Run a block on a particular platform**
45
+
46
+ The following example shows how an if statement can be used with the `windows?` method in the Chef Infra Language to run code specific to Microsoft Windows. The code is defined using the ruby_block resource:
47
+
48
+ ```ruby
49
+ if windows?
50
+ ruby_block 'copy libmysql.dll into ruby path' do
51
+ block do
52
+ require 'fileutils'
53
+ FileUtils.cp "#{node['mysql']['client']['lib_dir']}\\libmysql.dll",
54
+ node['mysql']['client']['ruby_dir']
55
+ end
56
+ not_if { ::File.exist?("#{node['mysql']['client']['ruby_dir']}\\libmysql.dll") }
57
+ end
58
+ end
59
+ ```
60
+
61
+ **Stash a file in a data bag**
62
+
63
+ The following example shows how to use the ruby_block resource to stash a BitTorrent file in a data bag so that it can be distributed to nodes in the organization.
64
+
65
+ ```ruby
66
+ ruby_block 'share the torrent file' do
67
+ block do
68
+ f = File.open(node['bittorrent']['torrent'],'rb')
69
+ #read the .torrent file and base64 encode it
70
+ enc = Base64.encode64(f.read)
71
+ data = {
72
+ 'id'=>bittorrent_item_id(node['bittorrent']['file']),
73
+ 'seed'=>node.ipaddress,
74
+ 'torrent'=>enc
75
+ }
76
+ item = Chef::DataBagItem.new
77
+ item.data_bag('bittorrent')
78
+ item.raw_data = data
79
+ item.save
80
+ end
81
+ action :nothing
82
+ subscribes :create, "bittorrent_torrent[#{node['bittorrent']['torrent']}]", :immediately
83
+ end
84
+ ```
85
+
86
+ **Update the /etc/hosts file**
87
+
88
+ The following example shows how the ruby_block resource can be used to update the /etc/hosts file:
89
+
90
+ ```ruby
91
+ ruby_block 'edit etc hosts' do
92
+ block do
93
+ rc = Chef::Util::FileEdit.new('/etc/hosts')
94
+ rc.search_file_replace_line(/^127\.0\.0\.1 localhost$/,
95
+ '127.0.0.1 #{new_fqdn} #{new_hostname} localhost')
96
+ rc.write_file
97
+ end
98
+ end
99
+ ```
100
+
101
+ **Set environment variables**
102
+
103
+ The following example shows how to use variables within a Ruby block to set environment variables using rbenv.
104
+
105
+ ```ruby
106
+ node.override[:rbenv][:root] = rbenv_root
107
+ node.override[:ruby_build][:bin_path] = rbenv_binary_path
108
+
109
+ ruby_block 'initialize' do
110
+ block do
111
+ ENV['RBENV_ROOT'] = node[:rbenv][:root]
112
+ ENV['PATH'] = "#{node[:rbenv][:root]}/bin:#{node[:ruby_build][:bin_path]}:#{ENV['PATH']}"
113
+ end
114
+ end
115
+ ```
116
+
117
+ **Call methods in a gem**
118
+
119
+ The following example shows how to call methods in gems not shipped in Chef Infra Client
120
+
121
+ ```ruby
122
+ chef_gem 'mongodb'
123
+
124
+ ruby_block 'config_replicaset' do
125
+ block do
126
+ MongoDB.configure_replicaset(node, replicaset_name, rs_nodes)
127
+ end
128
+ action :run
129
+ end
130
+ ```
131
+ DOC
32
132
 
33
133
  default_action :run
34
134
  allowed_actions :create, :run
@@ -28,7 +28,7 @@ class Chef
28
28
 
29
29
  provides :subversion
30
30
 
31
- description "Use the **subversion** resource to manage source control resources that exist in a Subversion repository."
31
+ description "Use the **subversion** resource to manage source control resources that exist in a Subversion repository. Warning: The subversion resource has known bugs and may not work as expected. For more information see Chef GitHub issues, particularly [#4050](https://github.com/chef/chef/issues/4050) and [#4257](https://github.com/chef/chef/issues/4257)."
32
32
  examples <<~DOC
33
33
  **Get the latest version of an application**
34
34
 
@@ -131,7 +131,7 @@ class Chef
131
131
 
132
132
  end
133
133
 
134
- action :apply, description: "Apply a sysctl value." do
134
+ action :apply, description: "Set the kernel parameter and update the `sysctl` settings." do
135
135
  converge_if_changed do
136
136
  # set it temporarily
137
137
  set_sysctl_param(new_resource.key, new_resource.value)
@@ -150,7 +150,7 @@ class Chef
150
150
  end
151
151
  end
152
152
 
153
- action :remove, description: "Remove a sysctl value." do
153
+ action :remove, description: "Remove the kernel parameter and update the `sysctl` settings." do
154
154
  # only converge the resource if the file actually exists to delete
155
155
  if ::File.exist?("#{new_resource.conf_dir}/99-chef-#{new_resource.key.tr("/", ".")}.conf")
156
156
  converge_by "removing sysctl config at #{new_resource.conf_dir}/99-chef-#{new_resource.key.tr("/", ".")}.conf" do
@@ -34,7 +34,7 @@ class Chef
34
34
 
35
35
  ```ruby
36
36
  systemd_unit 'etcd.service' do
37
- content(Unit: {
37
+ content({ Unit: {
38
38
  Description: 'Etcd',
39
39
  Documentation: ['https://coreos.com/etcd', 'man:etcd(1)'],
40
40
  After: 'network.target',
@@ -46,7 +46,7 @@ class Chef
46
46
  },
47
47
  Install: {
48
48
  WantedBy: 'multi-user.target',
49
- })
49
+ } })
50
50
  action [:create, :enable]
51
51
  end
52
52
  ```
@@ -113,7 +113,7 @@ class Chef
113
113
  when Hash
114
114
  IniParse.gen do |doc|
115
115
  content.each_pair do |sect, opts|
116
- doc.section(sect) do |section|
116
+ doc.section(sect, { option_sep: "=" }) do |section|
117
117
  opts.each_pair do |opt, val|
118
118
  [val].flatten.each do |v|
119
119
  section.option(opt, v)
@@ -27,11 +27,7 @@ class Chef
27
27
  provides :yum_package
28
28
  provides :package, platform_family: "fedora_derived"
29
29
 
30
- description "Use the **yum_package** resource to install, upgrade, and remove packages with Yum"\
31
- " for the Red Hat and CentOS platforms. The yum_package resource is able to resolve"\
32
- " `provides` data for packages much like Yum can do when it is run from the command line."\
33
- " This allows a variety of options for installing packages, like minimum versions,"\
34
- " virtual provides, and library names."
30
+ description "Use the **yum_package** resource to install, upgrade, and remove packages with Yum for the Red Hat and CentOS platforms. The yum_package resource is able to resolve `provides` data for packages much like Yum can do when it is run from the command line. This allows a variety of options for installing packages, like minimum versions, virtual provides, and library names. Note: Support for using file names to install packages (as in `yum_package '/bin/sh'`) is not available because the volume of data required to parse for this is excessive."
35
31
  examples <<~DOC
36
32
  **Install an exact version**:
37
33
 
data/lib/chef/resource.rb CHANGED
@@ -1063,7 +1063,8 @@ class Chef
1063
1063
  # action for the resource.
1064
1064
  #
1065
1065
  # @param name [Symbol] The action name to define.
1066
- # @param description [String] optional description for the action
1066
+ # @param description [String] optional description for the action. Used for
1067
+ # documentation generation.
1067
1068
  # @param recipe_block The recipe to run when the action is taken. This block
1068
1069
  # takes no parameters, and will be evaluated in a new context containing:
1069
1070
  #
@@ -1076,11 +1077,8 @@ class Chef
1076
1077
  def self.action(action, description: nil, &recipe_block)
1077
1078
  action = action.to_sym
1078
1079
  declare_action_class
1079
- action_class.action(action, &recipe_block)
1080
+ action_class.action(action, description: description, &recipe_block)
1080
1081
  self.allowed_actions += [ action ]
1081
- # Accept any non-nil description, which will correctly override
1082
- # any specific inherited description.
1083
- action_descriptions[action] = description unless description.nil?
1084
1082
  default_action action if Array(default_action) == [:nothing]
1085
1083
  end
1086
1084
 
@@ -1090,18 +1088,15 @@ class Chef
1090
1088
  # @param action [Symbol,String] the action name
1091
1089
  # @return the description of the action provided, or nil if no description
1092
1090
  # was defined
1093
- def self.action_description(action)
1094
- action_descriptions[action.to_sym]
1095
- end
1096
-
1097
- # @api private
1098
- #
1099
- # @return existing action description hash, or newly-initialized
1100
- # hash containing action descriptions inherited from parent Resource,
1101
- # if any.
1102
- def self.action_descriptions
1103
- @action_descriptions ||=
1104
- superclass.respond_to?(:action_descriptions) ? superclass.action_descriptions.dup : { nothing: nil }
1091
+ def action_description(action)
1092
+ provider_for_action(action).class.action_description(action)
1093
+ rescue Chef::Exceptions::ProviderNotFound
1094
+ # If a provider can't be found, there can be no description defined on the provider.
1095
+ nil
1096
+ rescue NameError => e
1097
+ # This can happen when attempting to load a provider in a platform-specific
1098
+ # environment where we have not required the necessary files yet
1099
+ raise unless e.message =~ /uninitialized constant/
1105
1100
  end
1106
1101
 
1107
1102
  # Define a method to load up this resource's properties with the current
@@ -1188,9 +1183,10 @@ class Chef
1188
1183
  begin
1189
1184
  is_custom_resource!
1190
1185
  base_provider =
1191
- if superclass.custom_resource?
1186
+ if superclass.custom_resource? || superclass != Chef::Resource
1192
1187
  superclass.action_class
1193
1188
  else
1189
+
1194
1190
  ActionClass
1195
1191
  end
1196
1192
 
@@ -23,6 +23,11 @@ require_relative "node"
23
23
  require_relative "resources"
24
24
  require_relative "json_compat"
25
25
 
26
+ # We need to require providers so that we can resolve
27
+ # action documentation that may have been defined on the providers
28
+ # instead of the resources.
29
+ require_relative "providers"
30
+
26
31
  class Chef
27
32
  module ResourceInspector
28
33
  def self.get_default(default)
@@ -39,11 +44,10 @@ class Chef
39
44
  def self.extract_resource(resource, complete = false)
40
45
  data = {}
41
46
  data[:description] = resource.description
42
- # data[:deprecated] = resource.deprecated || false
43
47
  data[:default_action] = resource.default_action
44
48
  data[:actions] = {}
45
49
  resource.allowed_actions.each do |action|
46
- data[:actions][action] = resource.action_description(action)
50
+ data[:actions][action] = resource.new(resource.to_s, nil).action_description(action)
47
51
  end
48
52
 
49
53
  data[:examples] = resource.examples
@@ -17,6 +17,7 @@
17
17
  #
18
18
 
19
19
  require_relative "base"
20
+ require "aws-sdk-core"
20
21
  require "aws-sdk-secretsmanager"
21
22
 
22
23
  class Chef
@@ -26,19 +27,30 @@ class Chef
26
27
  # It is possible to pass options that configure it to use alternative credentials.
27
28
  # This implementation supports fetching with version.
28
29
  #
29
- # NOTE: This does not yet support automatic retries, which the AWS client does by default.
30
+ # @note ':region' is required configuration. If it is not explicitly provided,
31
+ # and it is not available via global AWS config, we will pull it from node ohai data by default.
32
+ # If this isn't correct, you will need to explicitly override it.
33
+ # If it is not available via ohai data either (such as if you have the AWS plugin disabled)
34
+ # then the converge will fail with an error.
35
+ #
36
+ # @note: This does not yet support automatic retries, which the AWS client does by default.
30
37
  #
31
38
  # For configuration options see https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SecretsManager/Client.html#initialize-instance_method
32
39
  #
33
- # Note that ~/.aws default and environment-based configurations are supported by default in the
34
- # ruby SDK.
35
40
  #
36
41
  # Usage Example:
37
42
  #
38
- # fetcher = SecretFetcher.for_service(:aws_secrets_manager, { region: "us-east-1" })
43
+ # fetcher = SecretFetcher.for_service(:aws_secrets_manager)
39
44
  # fetcher.fetch("secretkey1", "v1")
40
45
  class SecretFetcher
41
46
  class AWSSecretsManager < Base
47
+ def validate!
48
+ config[:region] = config[:region] || Aws.config[:region] || run_context.node.dig("ec2", "region")
49
+ if config[:region].nil?
50
+ raise Chef::Exceptions::Secret::ConfigurationInvalid.new("Missing required config for AWS secret fetcher: :region")
51
+ end
52
+ end
53
+
42
54
  # @param identifier [String] the secret_id
43
55
  # @param version [String] the secret version. Not usd at this time
44
56
  # @return Aws::SecretsManager::Types::GetSecretValueResponse