diff options
59 files changed, 820 insertions, 171 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f377e8957..2221b43468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,24 @@ <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ --> -<!-- latest_release 14.2.2 --> -## [v14.2.2](https://github.com/chef/chef/tree/v14.2.2) (2018-06-07) +<!-- latest_release 14.3.6 --> +## [v14.3.6](https://github.com/chef/chef/tree/v14.3.6) (2018-06-11) #### Merged Pull Requests -- Expand development docs with branch/backport + more [#7343](https://github.com/chef/chef/pull/7343) ([tas50](https://github.com/tas50)) +- Add kernel_module resource from the kernel_module cookbook [#7165](https://github.com/chef/chef/pull/7165) ([tas50](https://github.com/tas50)) <!-- latest_release --> <!-- release_rollup since=14.2.0 --> ### Changes since 14.2.0 release #### Merged Pull Requests +- Add kernel_module resource from the kernel_module cookbook [#7165](https://github.com/chef/chef/pull/7165) ([tas50](https://github.com/tas50)) <!-- 14.3.6 --> +- Add ssh_known_hosts_entry resource from ssh_known_hosts cookbook [#7161](https://github.com/chef/chef/pull/7161) ([tas50](https://github.com/tas50)) <!-- 14.3.5 --> +- Update help link in Add/Remove Programs on Windows [#7345](https://github.com/chef/chef/pull/7345) ([stuartpreston](https://github.com/stuartpreston)) <!-- 14.3.4 --> +- Implement rfc107: NodeMap locking for resource and provider handlers [#7224](https://github.com/chef/chef/pull/7224) ([coderanger](https://github.com/coderanger)) <!-- 14.3.4 --> +- Add whyrun message when installing a local file on Windows [#7351](https://github.com/chef/chef/pull/7351) ([josh-barker](https://github.com/josh-barker)) <!-- 14.3.3 --> +- Make shell_out_compact automatically pull timeouts off the resource + remove uses of shell_out_compact_timeout [#7330](https://github.com/chef/chef/pull/7330) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 14.3.2 --> +- Deprecated the Chef::Provider::Package::Freebsd::Pkg provider [#7350](https://github.com/chef/chef/pull/7350) ([tas50](https://github.com/tas50)) <!-- 14.3.1 --> +- Bump the version to 14.3.0 [#7346](https://github.com/chef/chef/pull/7346) ([tas50](https://github.com/tas50)) <!-- 14.3.0 --> +- Support windows_feature_powershell on Windows 2008 R2 [#7349](https://github.com/chef/chef/pull/7349) ([tas50](https://github.com/tas50)) <!-- 14.2.3 --> - Add skip_publisher_check property to powershell_package [#7259](https://github.com/chef/chef/pull/7259) ([Happycoil](https://github.com/Happycoil)) <!-- 14.2.1 --> - Expand development docs with branch/backport + more [#7343](https://github.com/chef/chef/pull/7343) ([tas50](https://github.com/tas50)) <!-- 14.2.2 --> <!-- release_rollup --> diff --git a/Gemfile.lock b/Gemfile.lock index 35c5e1ce65..de9ce3d23c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,10 +9,10 @@ GIT PATH remote: . specs: - chef (14.2.2) + chef (14.3.6) addressable bundler (>= 1.10) - chef-config (= 14.2.2) + chef-config (= 14.3.6) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -40,10 +40,10 @@ PATH specinfra (~> 2.10) syslog-logger (~> 1.6) uuidtools (~> 2.1.5) - chef (14.2.2-universal-mingw32) + chef (14.3.6-universal-mingw32) addressable bundler (>= 1.10) - chef-config (= 14.2.2) + chef-config (= 14.3.6) chef-zero (>= 13.0) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) @@ -86,7 +86,7 @@ PATH PATH remote: chef-config specs: - chef-config (14.2.2) + chef-config (14.3.6) addressable fuzzyurl mixlib-config (~> 2.0) @@ -175,9 +175,9 @@ GEM addressable (~> 2.3) libyajl2 (1.2.0) method_source (0.9.0) - mixlib-archive (0.4.6) + mixlib-archive (0.4.7) mixlib-log - mixlib-authentication (2.1.0) + mixlib-authentication (2.1.1) mixlib-cli (1.7.0) mixlib-config (2.2.6) tomlrb @@ -1 +1 @@ -14.2.2
\ No newline at end of file +14.3.6
\ No newline at end of file diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb index a9cae3a2da..8c488e6a5b 100644 --- a/chef-config/lib/chef-config/version.rb +++ b/chef-config/lib/chef-config/version.rb @@ -21,7 +21,7 @@ module ChefConfig CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__) - VERSION = "14.2.2" + VERSION = "14.3.6" end # diff --git a/kitchen-tests/cookbooks/base/recipes/default.rb b/kitchen-tests/cookbooks/base/recipes/default.rb index ea0215ca96..9175bfbd26 100644 --- a/kitchen-tests/cookbooks/base/recipes/default.rb +++ b/kitchen-tests/cookbooks/base/recipes/default.rb @@ -38,6 +38,9 @@ users_manage "sysadmin" do action [:create] end +ssh_known_hosts_entry "github.com" +ssh_known_hosts_entry "travis.org" + sudo "sysadmins" do group ["sysadmin", "%superadmin"] nopasswd true diff --git a/lib/chef/client.rb b/lib/chef/client.rb index 7218c3bb49..33d625c54e 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -275,6 +275,9 @@ class Chef do_windows_admin_check + Chef.resource_handler_map.lock! + Chef.provider_handler_map.lock! + run_context = setup_run_context load_required_recipe(@rest, run_context) unless Chef::Config[:solo_legacy_mode] diff --git a/lib/chef/deprecated.rb b/lib/chef/deprecated.rb index 792df69f71..904578ff0b 100644 --- a/lib/chef/deprecated.rb +++ b/lib/chef/deprecated.rb @@ -278,6 +278,16 @@ class Chef end end + class FreebsdPkgProvider < Base + def id + 23 + end + + def target + "freebsd_pkg_provider.html" + end + end + # id 3694 was deleted # Returned when using the deprecated option on a property diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb index 236ef844b1..e7010bb989 100644 --- a/lib/chef/mixin/shell_out.rb +++ b/lib/chef/mixin/shell_out.rb @@ -62,6 +62,7 @@ class Chef # def shell_out_compact(*args, **options) + options = Chef::Mixin::ShellOut.maybe_add_timeout(self, options) if options.empty? shell_out(*clean_array(*args)) else @@ -70,6 +71,7 @@ class Chef end def shell_out_compact!(*args, **options) + options = Chef::Mixin::ShellOut.maybe_add_timeout(self, options) if options.empty? shell_out!(*clean_array(*args)) else @@ -78,21 +80,24 @@ class Chef end # helper sugar for resources that support passing timeouts to shell_out + # + # module method to not pollute namespaces, but that means we need self injected as an arg + # @api private + def self.maybe_add_timeout(obj, options) + if obj.is_a?(Chef::Provider) && !obj.new_resource.is_a?(Chef::Resource::LWRPBase) && obj.new_resource.respond_to?(:timeout) && !options.key?(:timeout) + options = options.dup + # historically resources have not properly declared defaults on their timeouts, so a default default of 900s was enforced here + options[:timeout] = obj.new_resource.timeout ? obj.new_resource.timeout.to_f : 900 + end + options + end def shell_out_compact_timeout(*args, **options) - raise "object is not a resource that supports timeouts" unless respond_to?(:new_resource) && new_resource.respond_to?(:timeout) - options_dup = options.dup - options_dup[:timeout] = new_resource.timeout if new_resource.timeout - options_dup[:timeout] = 900 unless options_dup.key?(:timeout) - shell_out_compact(*args, **options_dup) + shell_out_compact(*args, **options) end def shell_out_compact_timeout!(*args, **options) - raise "object is not a resource that supports timeouts" unless respond_to?(:new_resource) && new_resource.respond_to?(:timeout) - options_dup = options.dup - options_dup[:timeout] = new_resource.timeout if new_resource.timeout - options_dup[:timeout] = 900 unless options_dup.key?(:timeout) - shell_out_compact!(*args, **options_dup) + shell_out_compact!(*args, **options) end # shell_out! runs a command on the system and will raise an error if the command fails, which is what you want diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb index 0406b3c1d6..634786af93 100644 --- a/lib/chef/node_map.rb +++ b/lib/chef/node_map.rb @@ -45,12 +45,18 @@ class Chef # @param key [Object] Key to store # @param value [Object] Value associated with the key # @param filters [Hash] Node filter options to apply to key retrieval + # @param allow_cookbook_override [Boolean, String] Allow a cookbook to add + # to this key even in locked mode. If a string is given, it should be a + # Gem::Requirement-compatible value indicating for which Chef versions an + # override from cookbooks is allowed. + # @param __core_override__ [Boolean] Advanced-mode override to add to a key + # even in locked mode. # # @yield [node] Arbitrary node filter as a block which takes a node argument # # @return [NodeMap] Returns self for possible chaining # - def set(key, klass, platform: nil, platform_version: nil, platform_family: nil, os: nil, canonical: nil, override: nil, &block) + def set(key, klass, platform: nil, platform_version: nil, platform_family: nil, os: nil, canonical: nil, override: nil, allow_cookbook_override: false, __core_override__: false, &block) # rubocop:disable Lint/UnderscorePrefixedVariableName new_matcher = { klass: klass } new_matcher[:platform] = platform if platform new_matcher[:platform_version] = platform_version if platform_version @@ -59,6 +65,31 @@ class Chef new_matcher[:block] = block if block new_matcher[:canonical] = canonical if canonical new_matcher[:override] = override if override + new_matcher[:cookbook_override] = allow_cookbook_override + new_matcher[:core_override] = __core_override__ + + # Check if the key is already present and locked, unless the override is allowed. + # The checks to see if we should reject, in order: + # 1. Core override mode is not set. + # 2. The key exists. + # 3. At least one previous `provides` is now locked. + # 4. No previous `provides` had `allow_cookbook_override`, either set to + # true or with a string version matcher that still matches Chef::VERSION + if !__core_override__ && map[key] && map[key].any? { |matcher| matcher[:locked] } && !map[key].any? { |matcher| matcher[:cookbook_override].is_a?(String) ? Chef::VERSION =~ matcher[:cookbook_override] : matcher[:cookbook_override] } + # If we ever use locked mode on things other than the resource and provider handler maps, this probably needs a tweak. + type_of_thing = if klass < Chef::Resource + "resource" + elsif klass < Chef::Provider + "provider" + else + klass.superclass.to_s + end + # For now, only log the warning. + Chef.log_deprecation("Trying to register #{type_of_thing} #{key} on top of existing Chef core #{type_of_thing}. Check if a new version of the cookbook is available.") + # In 15.0, uncomment this and remove the log above. + # Chef.log_deprecation("Rejecting attempt to register #{type_of_thing} #{key} on top of existing Chef core #{type_of_thing}. Check if a new version of the cookbook is available.") + # return + end # The map is sorted in order of preference already; we just need to find # our place in it (just before the first value with the same preference level). @@ -159,6 +190,34 @@ class Chef remaining end + # Check if this map has been locked. + # + # @api internal + # @since 14.2 + # @return [Boolean] + def locked? + if defined?(@locked) + @locked + else + false + end + end + + # Set this map to locked mode. This is used to prevent future overwriting + # of existing names. + # + # @api internal + # @since 14.2 + # @return [void] + def lock! + map.each do |key, matchers| + matchers.each do |matcher| + matcher[:locked] = true + end + end + @locked = true + end + private # diff --git a/lib/chef/platform/query_helpers.rb b/lib/chef/platform/query_helpers.rb index b49010efc0..448885dfbc 100644 --- a/lib/chef/platform/query_helpers.rb +++ b/lib/chef/platform/query_helpers.rb @@ -20,6 +20,12 @@ class Chef class Platform class << self + # a simple helper to determine if we're on a windows release pre-2012 / 8 + # @return [Boolean] Is the system older than Windows 8 / 2012 + def older_than_win_2012_or_8? + node["platform_version"].to_f < 6.2 + end + def windows? ChefConfig.windows? end diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index 133f87dad9..6a7b2bc276 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -307,7 +307,7 @@ class Chef # used by subclasses. deprecated. use #a_to_s instead. def expand_options(options) # its deprecated but still work to do to deprecate it fully - #Chef.deprecated(:package_misc, "expand_options is deprecated, use shell_out_compact or shell_out_compact_timeout instead") + #Chef.deprecated(:package_misc, "expand_options is deprecated, use shell_out_compact instead") if options " #{options.is_a?(Array) ? Shellwords.join(options) : options}" else @@ -678,7 +678,7 @@ class Chef def add_timeout_option(command_args) # this is deprecated but its not quite done yet - #Chef.deprecated(:package_misc, "shell_out_with_timeout and add_timeout_option are deprecated methods, use shell_out_compact_timeout instead") + #Chef.deprecated(:package_misc, "shell_out_with_timeout and add_timeout_option are deprecated methods, use shell_out_compact instead") args = command_args.dup if args.last.is_a?(Hash) options = args.pop.dup diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb index 798abf4680..b644848442 100644 --- a/lib/chef/provider/package/apt.rb +++ b/lib/chef/provider/package/apt.rb @@ -81,7 +81,7 @@ class Chef def locked_packages @locked_packages ||= begin - locked = shell_out_compact_timeout!("apt-mark", "showhold") + locked = shell_out_compact!("apt-mark", "showhold") locked.stdout.each_line.map do |line| line.strip end @@ -140,9 +140,9 @@ class Chef # # @return [Integer] 1 if v1 > v2. 0 if they're equal. -1 if v1 < v2 def version_compare(v1, v2) - if !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "gt", v2.to_s).error? + if !shell_out_compact("dpkg", "--compare-versions", v1.to_s, "gt", v2.to_s).error? 1 - elsif !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "eq", v2.to_s).error? + elsif !shell_out_compact("dpkg", "--compare-versions", v1.to_s, "eq", v2.to_s).error? 0 else -1 @@ -153,7 +153,7 @@ class Chef # interactive prompts. Command is run with default localization rather # than forcing locale to "C", so command output may not be stable. def run_noninteractive(*args) - shell_out_compact_timeout!(*args, env: { "DEBIAN_FRONTEND" => "noninteractive" }) + shell_out_compact!(*args, env: { "DEBIAN_FRONTEND" => "noninteractive" }) end def default_release_options diff --git a/lib/chef/provider/package/bff.rb b/lib/chef/provider/package/bff.rb index 44fadd92df..6f103c63ac 100644 --- a/lib/chef/provider/package/bff.rb +++ b/lib/chef/provider/package/bff.rb @@ -49,7 +49,7 @@ class Chef if package_source_found? logger.trace("#{new_resource} checking pkg status") - ret = shell_out_compact_timeout("installp", "-L", "-d", new_resource.source) + ret = shell_out_compact("installp", "-L", "-d", new_resource.source) ret.stdout.each_line do |line| case line when /:#{new_resource.package_name}:/ @@ -65,7 +65,7 @@ class Chef end logger.trace("#{new_resource} checking install state") - ret = shell_out_compact_timeout("lslpp", "-lcq", current_resource.package_name) + ret = shell_out_compact("lslpp", "-lcq", current_resource.package_name) ret.stdout.each_line do |line| case line when /#{current_resource.package_name}/ @@ -85,7 +85,7 @@ class Chef def candidate_version return @candidate_version if @candidate_version if package_source_found? - ret = shell_out_compact_timeout("installp", "-L", "-d", new_resource.source) + ret = shell_out_compact("installp", "-L", "-d", new_resource.source) ret.stdout.each_line do |line| case line when /\w:#{Regexp.escape(new_resource.package_name)}:(.*)/ @@ -112,10 +112,10 @@ class Chef def install_package(name, version) logger.trace("#{new_resource} package install options: #{options}") if options.nil? - shell_out_compact_timeout!("installp", "-aYF", "-d", new_resource.source, new_resource.package_name) + shell_out_compact!("installp", "-aYF", "-d", new_resource.source, new_resource.package_name) logger.trace("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}") else - shell_out_compact_timeout!("installp", "-aYF", options, "-d", new_resource.source, new_resource.package_name) + shell_out_compact!("installp", "-aYF", options, "-d", new_resource.source, new_resource.package_name) logger.trace("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}") end end @@ -124,10 +124,10 @@ class Chef def remove_package(name, version) if options.nil? - shell_out_compact_timeout!("installp", "-u", name) + shell_out_compact!("installp", "-u", name) logger.trace("#{new_resource} removed version #{new_resource.version}") else - shell_out_compact_timeout!("installp", "-u", options, name) + shell_out_compact!("installp", "-u", options, name) logger.trace("#{new_resource} removed version #{new_resource.version}") end end diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb index b18a284116..0233c0a838 100644 --- a/lib/chef/provider/package/dnf.rb +++ b/lib/chef/provider/package/dnf.rb @@ -167,7 +167,7 @@ class Chef end def dnf(*args) - shell_out_compact_timeout!("dnf", *args) + shell_out_compact!("dnf", *args) end def safe_version_array diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb index aa53f6145f..0b6a9c8ba2 100644 --- a/lib/chef/provider/package/dpkg.rb +++ b/lib/chef/provider/package/dpkg.rb @@ -113,9 +113,9 @@ class Chef # # @return [Integer] 1 if v1 > v2. 0 if they're equal. -1 if v1 < v2 def version_compare(v1, v2) - if !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "gt", v2.to_s).error? + if !shell_out_compact("dpkg", "--compare-versions", v1.to_s, "gt", v2.to_s).error? 1 - elsif !shell_out_compact_timeout("dpkg", "--compare-versions", v1.to_s, "eq", v2.to_s).error? + elsif !shell_out_compact("dpkg", "--compare-versions", v1.to_s, "eq", v2.to_s).error? 0 else -1 @@ -124,7 +124,7 @@ class Chef def read_current_version_of_package(package_name) logger.trace("#{new_resource} checking install state of #{package_name}") - status = shell_out_compact_timeout!("dpkg", "-s", package_name, returns: [0, 1]) + status = shell_out_compact!("dpkg", "-s", package_name, returns: [0, 1]) package_installed = false status.stdout.each_line do |line| case line @@ -152,7 +152,7 @@ class Chef # Runs command via shell_out_with_timeout with magic environment to disable # interactive prompts. def run_noninteractive(*command) - shell_out_compact_timeout!(*command, env: { "DEBIAN_FRONTEND" => "noninteractive" }) + shell_out_compact!(*command, env: { "DEBIAN_FRONTEND" => "noninteractive" }) end # Returns true if all sources exist. Returns false if any do not, or if no @@ -192,7 +192,7 @@ class Chef begin pkginfos = resolved_source_array.map do |src| logger.trace("#{new_resource} checking #{src} dpkg status") - status = shell_out_compact_timeout!("dpkg-deb", "-W", src) + status = shell_out_compact!("dpkg-deb", "-W", src) status.stdout end Hash[*package_name_array.zip(pkginfos).flatten] diff --git a/lib/chef/provider/package/freebsd/base.rb b/lib/chef/provider/package/freebsd/base.rb index fc62fa7cc0..c9b3bf222b 100644 --- a/lib/chef/provider/package/freebsd/base.rb +++ b/lib/chef/provider/package/freebsd/base.rb @@ -47,7 +47,7 @@ class Chef # Otherwise look up the path to the ports directory using 'whereis' else - whereis = shell_out_compact_timeout!("whereis", "-s", port, env: nil) + whereis = shell_out_compact!("whereis", "-s", port, env: nil) unless path = whereis.stdout[/^#{Regexp.escape(port)}:\s+(.+)$/, 1] raise Chef::Exceptions::Package, "Could not find port with the name #{port}" end @@ -57,7 +57,7 @@ class Chef def makefile_variable_value(variable, dir = nil) options = dir ? { cwd: dir } : {} - make_v = shell_out_compact_timeout!("make", "-V", variable, options.merge!(env: nil, returns: [0, 1])) + make_v = shell_out_compact!("make", "-V", variable, options.merge!(env: nil, returns: [0, 1])) make_v.exitstatus == 0 ? make_v.stdout.strip.split($OUTPUT_RECORD_SEPARATOR).first : nil # $\ is the line separator, i.e. newline. end end diff --git a/lib/chef/provider/package/freebsd/pkg.rb b/lib/chef/provider/package/freebsd/pkg.rb index 04e6e5c427..800bca681c 100644 --- a/lib/chef/provider/package/freebsd/pkg.rb +++ b/lib/chef/provider/package/freebsd/pkg.rb @@ -34,24 +34,24 @@ class Chef case new_resource.source when /^http/, /^ftp/ if new_resource.source =~ /\/$/ - shell_out_compact_timeout!("pkg_add", "-r", package_name, env: { "PACKAGESITE" => new_resource.source, "LC_ALL" => nil }).status + shell_out_compact!("pkg_add", "-r", package_name, env: { "PACKAGESITE" => new_resource.source, "LC_ALL" => nil }).status else - shell_out_compact_timeout!("pkg_add", "-r", package_name, env: { "PACKAGEROOT" => new_resource.source, "LC_ALL" => nil }).status + shell_out_compact!("pkg_add", "-r", package_name, env: { "PACKAGEROOT" => new_resource.source, "LC_ALL" => nil }).status end logger.trace("#{new_resource} installed from: #{new_resource.source}") when /^\// - shell_out_compact_timeout!("pkg_add", file_candidate_version_path, env: { "PKG_PATH" => new_resource.source, "LC_ALL" => nil }).status + shell_out_compact!("pkg_add", file_candidate_version_path, env: { "PKG_PATH" => new_resource.source, "LC_ALL" => nil }).status logger.trace("#{new_resource} installed from: #{new_resource.source}") else - shell_out_compact_timeout!("pkg_add", "-r", latest_link_name, env: nil).status + shell_out_compact!("pkg_add", "-r", latest_link_name, env: nil).status end end end def remove_package(name, version) - shell_out_compact_timeout!("pkg_delete", "#{package_name}-#{version || current_resource.version}", env: nil).status + shell_out_compact!("pkg_delete", "#{package_name}-#{version || current_resource.version}", env: nil).status end # The name of the package (without the version number) as understood by pkg_add and pkg_info. @@ -72,7 +72,7 @@ class Chef end def current_installed_version - pkg_info = shell_out_compact_timeout!("pkg_info", "-E", "#{package_name}*", env: nil, returns: [0, 1]) + pkg_info = shell_out_compact!("pkg_info", "-E", "#{package_name}*", env: nil, returns: [0, 1]) pkg_info.stdout[/^#{Regexp.escape(package_name)}-(.+)/, 1] end diff --git a/lib/chef/provider/package/freebsd/pkgng.rb b/lib/chef/provider/package/freebsd/pkgng.rb index c9c0947f9b..ab64753e88 100644 --- a/lib/chef/provider/package/freebsd/pkgng.rb +++ b/lib/chef/provider/package/freebsd/pkgng.rb @@ -28,21 +28,21 @@ class Chef unless current_resource.version case new_resource.source when /^(http|ftp|\/)/ - shell_out_compact_timeout!("pkg", "add", options, new_resource.source, env: { "LC_ALL" => nil }).status + shell_out_compact!("pkg", "add", options, new_resource.source, env: { "LC_ALL" => nil }).status logger.trace("#{new_resource} installed from: #{new_resource.source}") else - shell_out_compact_timeout!("pkg", "install", "-y", options, name, env: { "LC_ALL" => nil }).status + shell_out_compact!("pkg", "install", "-y", options, name, env: { "LC_ALL" => nil }).status end end end def remove_package(name, version) options_dup = options && options.map { |str| str.sub(repo_regex, "") }.reject!(&:empty?) - shell_out_compact_timeout!("pkg", "delete", "-y", options_dup, "#{name}#{version ? '-' + version : ''}", env: nil).status + shell_out_compact!("pkg", "delete", "-y", options_dup, "#{name}#{version ? '-' + version : ''}", env: nil).status end def current_installed_version - pkg_info = shell_out_compact_timeout!("pkg", "info", new_resource.package_name, env: nil, returns: [0, 70]) + pkg_info = shell_out_compact!("pkg", "info", new_resource.package_name, env: nil, returns: [0, 70]) pkg_info.stdout[/^Version +: (.+)$/, 1] end @@ -61,7 +61,7 @@ class Chef options = $1.split(" ") end - pkg_query = shell_out_compact_timeout!("pkg", "rquery", options, "%v", new_resource.package_name, env: nil) + pkg_query = shell_out_compact!("pkg", "rquery", options, "%v", new_resource.package_name, env: nil) pkg_query.exitstatus == 0 ? pkg_query.stdout.strip.split(/\n/).last : nil end diff --git a/lib/chef/provider/package/freebsd/port.rb b/lib/chef/provider/package/freebsd/port.rb index e87be4d304..96a96ad030 100644 --- a/lib/chef/provider/package/freebsd/port.rb +++ b/lib/chef/provider/package/freebsd/port.rb @@ -26,18 +26,18 @@ class Chef include PortsHelper def install_package(name, version) - shell_out_compact_timeout!("make", "-DBATCH", "install", "clean", timeout: 1800, env: nil, cwd: port_dir).status + shell_out_compact!("make", "-DBATCH", "install", "clean", timeout: 1800, env: nil, cwd: port_dir).status end def remove_package(name, version) - shell_out_compact_timeout!("make", "deinstall", timeout: 300, env: nil, cwd: port_dir).status + shell_out_compact!("make", "deinstall", timeout: 300, env: nil, cwd: port_dir).status end def current_installed_version pkg_info = if new_resource.supports_pkgng? - shell_out_compact_timeout!("pkg", "info", new_resource.package_name, env: nil, returns: [0, 70]) + shell_out_compact!("pkg", "info", new_resource.package_name, env: nil, returns: [0, 70]) else - shell_out_compact_timeout!("pkg_info", "-E", "#{new_resource.package_name}*", env: nil, returns: [0, 1]) + shell_out_compact!("pkg_info", "-E", "#{new_resource.package_name}*", env: nil, returns: [0, 1]) end pkg_info.stdout[/^#{Regexp.escape(new_resource.package_name)}-(.+)/, 1] end diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb index 643faf23c6..319ce992f7 100644 --- a/lib/chef/provider/package/homebrew.rb +++ b/lib/chef/provider/package/homebrew.rb @@ -128,7 +128,7 @@ class Chef logger.trace "Executing '#{command.join(' ')}' as user '#{homebrew_user.name}'" # FIXME: this 1800 second default timeout should be deprecated - output = shell_out_compact_timeout!(*command, timeout: 1800, user: homebrew_uid, environment: { "HOME" => homebrew_user.dir, "RUBYOPT" => nil, "TMPDIR" => nil }) + output = shell_out_compact!(*command, timeout: 1800, user: homebrew_uid, environment: { "HOME" => homebrew_user.dir, "RUBYOPT" => nil, "TMPDIR" => nil }) output.stdout.chomp end diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb index cabc7fc68b..3cd00084f0 100644 --- a/lib/chef/provider/package/ips.rb +++ b/lib/chef/provider/package/ips.rb @@ -42,14 +42,14 @@ class Chef end def get_current_version - shell_out_compact_timeout("pkg", "info", new_resource.package_name).stdout.each_line do |line| + shell_out_compact("pkg", "info", new_resource.package_name).stdout.each_line do |line| return $1.split[0] if line =~ /^\s+Version: (.*)/ end nil end def get_candidate_version - shell_out_compact_timeout!("pkg", "info", "-r", new_resource.package_name).stdout.each_line do |line| + shell_out_compact!("pkg", "info", "-r", new_resource.package_name).stdout.each_line do |line| return $1.split[0] if line =~ /Version: (.*)/ end nil @@ -68,7 +68,7 @@ class Chef command = [ "pkg", options, "install", "-q" ] command << "--accept" if new_resource.accept_license command << "#{name}@#{version}" - shell_out_compact_timeout!(command) + shell_out_compact!(command) end def upgrade_package(name, version) @@ -77,7 +77,7 @@ class Chef def remove_package(name, version) package_name = "#{name}@#{version}" - shell_out_compact_timeout!( "pkg", options, "uninstall", "-q", package_name ) + shell_out_compact!( "pkg", options, "uninstall", "-q", package_name ) end end end diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb index ddaf19a76f..50a04991a1 100644 --- a/lib/chef/provider/package/macports.rb +++ b/lib/chef/provider/package/macports.rb @@ -49,21 +49,21 @@ class Chef unless current_resource.version == version command = [ "port", options, "install", name ] command << "@#{version}" if version && !version.empty? - shell_out_compact_timeout!(command) + shell_out_compact!(command) end end def purge_package(name, version) command = [ "port", options, "uninstall", name ] command << "@#{version}" if version && !version.empty? - shell_out_compact_timeout!(command) + shell_out_compact!(command) end def remove_package(name, version) command = [ "port", options, "deactivate", name ] command << "@#{version}" if version && !version.empty? - shell_out_compact_timeout!(command) + shell_out_compact!(command) end def upgrade_package(name, version) @@ -76,7 +76,7 @@ class Chef # that hasn't been installed. install_package(name, version) elsif current_version != version - shell_out_compact_timeout!( "port", options, "upgrade", name, "@#{version}" ) + shell_out_compact!( "port", options, "upgrade", name, "@#{version}" ) end end @@ -84,7 +84,7 @@ class Chef def get_response_from_command(command) output = nil - status = shell_out_compact_timeout(command) + status = shell_out_compact(command) begin output = status.stdout rescue Exception diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb index f528c48f08..0bbe7abb60 100644 --- a/lib/chef/provider/package/openbsd.rb +++ b/lib/chef/provider/package/openbsd.rb @@ -72,7 +72,7 @@ class Chef if parts = name.match(/^(.+?)--(.+)/) # use double-dash for stems with flavors, see man page for pkg_add name = parts[1] end - shell_out_compact_timeout!("pkg_add", "-r", package_string(name, version), env: { "PKG_PATH" => pkg_path }).status + shell_out_compact!("pkg_add", "-r", package_string(name, version), env: { "PKG_PATH" => pkg_path }).status logger.trace("#{new_resource.package_name} installed") end end @@ -81,7 +81,7 @@ class Chef if parts = name.match(/^(.+?)--(.+)/) name = parts[1] end - shell_out_compact_timeout!("pkg_delete", package_string(name, version), env: nil).status + shell_out_compact!("pkg_delete", package_string(name, version), env: nil).status end private @@ -92,7 +92,7 @@ class Chef else new_resource.package_name end - pkg_info = shell_out_compact_timeout!("pkg_info", "-e", "#{name}->0", env: nil, returns: [0, 1]) + pkg_info = shell_out_compact!("pkg_info", "-e", "#{name}->0", env: nil, returns: [0, 1]) result = pkg_info.stdout[/^inst:#{Regexp.escape(name)}-(.+?)\s/, 1] logger.trace("installed_version of '#{new_resource.package_name}' is '#{result}'") result @@ -101,7 +101,7 @@ class Chef def candidate_version @candidate_version ||= begin results = [] - shell_out_compact_timeout!("pkg_info", "-I", package_string(new_resource.package_name, new_resource.version), env: nil, returns: [0, 1]).stdout.each_line do |line| + shell_out_compact!("pkg_info", "-I", package_string(new_resource.package_name, new_resource.version), env: nil, returns: [0, 1]).stdout.each_line do |line| results << if parts = new_resource.package_name.match(/^(.+?)--(.+)/) line[/^#{Regexp.escape(parts[1])}-(.+?)\s/, 1] else diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb index f6dde66219..2f08ee7d28 100644 --- a/lib/chef/provider/package/pacman.rb +++ b/lib/chef/provider/package/pacman.rb @@ -32,7 +32,7 @@ class Chef current_resource.package_name(new_resource.package_name) logger.trace("#{new_resource} checking pacman for #{new_resource.package_name}") - status = shell_out_compact_timeout("pacman", "-Qi", new_resource.package_name) + status = shell_out_compact("pacman", "-Qi", new_resource.package_name) status.stdout.each_line do |line| case line when /^Version(\s?)*: (.+)$/ @@ -60,7 +60,7 @@ class Chef package_repos = repos.map { |r| Regexp.escape(r) }.join("|") - status = shell_out_compact_timeout("pacman", "-Sl") + status = shell_out_compact("pacman", "-Sl") status.stdout.each_line do |line| case line when /^(#{package_repos}) #{Regexp.escape(new_resource.package_name)} (.+)$/ @@ -82,7 +82,7 @@ class Chef end def install_package(name, version) - shell_out_compact_timeout!( "pacman", "--sync", "--noconfirm", "--noprogressbar", options, name) + shell_out_compact!( "pacman", "--sync", "--noconfirm", "--noprogressbar", options, name) end def upgrade_package(name, version) @@ -90,7 +90,7 @@ class Chef end def remove_package(name, version) - shell_out_compact_timeout!( "pacman", "--remove", "--noconfirm", "--noprogressbar", options, name ) + shell_out_compact!( "pacman", "--remove", "--noconfirm", "--noprogressbar", options, name ) end def purge_package(name, version) diff --git a/lib/chef/provider/package/paludis.rb b/lib/chef/provider/package/paludis.rb index f6274d7553..50267610c2 100644 --- a/lib/chef/provider/package/paludis.rb +++ b/lib/chef/provider/package/paludis.rb @@ -58,7 +58,7 @@ class Chef else new_resource.package_name.to_s end - shell_out_compact_timeout!("cave", "-L", "warning", "resolve", "-x", options, pkg) + shell_out_compact!("cave", "-L", "warning", "resolve", "-x", options, pkg) end def upgrade_package(name, version) diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb index fecbba9dc9..4676f0ace4 100644 --- a/lib/chef/provider/package/portage.rb +++ b/lib/chef/provider/package/portage.rb @@ -1,6 +1,6 @@ # # Author:: Ezra Zygmuntowicz (<ezra@engineyard.com>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. +# Copyright:: Copyright 2008-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ class Chef PACKAGE_NAME_PATTERN = %r{(?:([^/]+)/)?([^/]+)} def load_current_resource - @current_resource = Chef::Resource::Package.new(new_resource.name) + @current_resource = Chef::Resource::PortagePackage.new(new_resource.name) current_resource.package_name(new_resource.package_name) category, pkg = /^#{PACKAGE_NAME_PATTERN}$/.match(new_resource.package_name)[1, 2] diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb index 9d4f2f3c23..9388e18860 100644 --- a/lib/chef/provider/package/rpm.rb +++ b/lib/chef/provider/package/rpm.rb @@ -57,7 +57,7 @@ class Chef end logger.trace("#{new_resource} checking rpm status") - shell_out_compact_timeout!("rpm", "-qp", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", new_resource.source).stdout.each_line do |line| + shell_out_compact!("rpm", "-qp", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", new_resource.source).stdout.each_line do |line| case line when /^(\S+)\s(\S+)$/ current_resource.package_name($1) @@ -73,7 +73,7 @@ class Chef end logger.trace("#{new_resource} checking install state") - @rpm_status = shell_out_compact_timeout("rpm", "-q", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", current_resource.package_name) + @rpm_status = shell_out_compact("rpm", "-q", "--queryformat", "%{NAME} %{VERSION}-%{RELEASE}\n", current_resource.package_name) @rpm_status.stdout.each_line do |line| case line when /^(\S+)\s(\S+)$/ @@ -88,12 +88,12 @@ class Chef def install_package(name, version) if current_resource.version if allow_downgrade - shell_out_compact_timeout!("rpm", options, "-U", "--oldpackage", new_resource.source) + shell_out_compact!("rpm", options, "-U", "--oldpackage", new_resource.source) else - shell_out_compact_timeout!("rpm", options, "-U", new_resource.source) + shell_out_compact!("rpm", options, "-U", new_resource.source) end else - shell_out_compact_timeout!("rpm", options, "-i", new_resource.source) + shell_out_compact!("rpm", options, "-i", new_resource.source) end end @@ -101,9 +101,9 @@ class Chef def remove_package(name, version) if version - shell_out_compact_timeout!("rpm", options, "-e", "#{name}-#{version}") + shell_out_compact!("rpm", options, "-e", "#{name}-#{version}") else - shell_out_compact_timeout!("rpm", options, "-e", name) + shell_out_compact!("rpm", options, "-e", name) end end diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb index 5c637814a6..e78fcec580 100644 --- a/lib/chef/provider/package/smartos.rb +++ b/lib/chef/provider/package/smartos.rb @@ -43,7 +43,7 @@ class Chef def check_package_state(name) logger.trace("#{new_resource} checking package #{name}") version = nil - info = shell_out_compact_timeout!("/opt/local/sbin/pkg_info", "-E", "#{name}*", env: nil, returns: [0, 1]) + info = shell_out_compact!("/opt/local/sbin/pkg_info", "-E", "#{name}*", env: nil, returns: [0, 1]) if info.stdout version = info.stdout[/^#{new_resource.package_name}-(.+)/, 1] @@ -58,7 +58,7 @@ class Chef return @candidate_version if @candidate_version name = nil version = nil - pkg = shell_out_compact_timeout!("/opt/local/bin/pkgin", "se", new_resource.package_name, env: nil, returns: [0, 1]) + pkg = shell_out_compact!("/opt/local/bin/pkgin", "se", new_resource.package_name, env: nil, returns: [0, 1]) pkg.stdout.each_line do |line| case line when /^#{new_resource.package_name}/ @@ -72,7 +72,7 @@ class Chef def install_package(name, version) logger.trace("#{new_resource} installing package #{name} version #{version}") package = "#{name}-#{version}" - out = shell_out_compact_timeout!("/opt/local/bin/pkgin", "-y", "install", package, env: nil) + out = shell_out_compact!("/opt/local/bin/pkgin", "-y", "install", package, env: nil) end def upgrade_package(name, version) @@ -83,7 +83,7 @@ class Chef def remove_package(name, version) logger.trace("#{new_resource} removing package #{name} version #{version}") package = name.to_s - out = shell_out_compact_timeout!("/opt/local/bin/pkgin", "-y", "remove", package, env: nil) + out = shell_out_compact!("/opt/local/bin/pkgin", "-y", "remove", package, env: nil) end end diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb index 9c75c76929..9f7cd3cd5d 100644 --- a/lib/chef/provider/package/solaris.rb +++ b/lib/chef/provider/package/solaris.rb @@ -55,7 +55,7 @@ class Chef @package_source_found = ::File.exist?(new_resource.source) if @package_source_found logger.trace("#{new_resource} checking pkg status") - shell_out_compact_timeout("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name).stdout.each_line do |line| + shell_out_compact("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name).stdout.each_line do |line| case line when /VERSION:\s+(.+)/ new_resource.version($1) @@ -65,7 +65,7 @@ class Chef end logger.trace("#{new_resource} checking install state") - status = shell_out_compact_timeout("pkginfo", "-l", current_resource.package_name) + status = shell_out_compact("pkginfo", "-l", current_resource.package_name) status.stdout.each_line do |line| case line when /VERSION:\s+(.+)/ @@ -83,7 +83,7 @@ class Chef def candidate_version return @candidate_version if @candidate_version - status = shell_out_compact_timeout("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name) + status = shell_out_compact("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name) status.stdout.each_line do |line| case line when /VERSION:\s+(.+)/ @@ -106,7 +106,7 @@ class Chef else [ "pkgadd", "-n", "-d", new_resource.source, "all" ] end - shell_out_compact_timeout!(command) + shell_out_compact!(command) logger.trace("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}") else command = if ::File.directory?(new_resource.source) # CHEF-4469 @@ -114,7 +114,7 @@ class Chef else [ "pkgadd", "-n", options, "-d", new_resource.source, "all" ] end - shell_out_compact_timeout!(*command) + shell_out_compact!(*command) logger.trace("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}") end end @@ -123,10 +123,10 @@ class Chef def remove_package(name, version) if options.nil? - shell_out_compact_timeout!( "pkgrm", "-n", name ) + shell_out_compact!( "pkgrm", "-n", name ) logger.trace("#{new_resource} removed version #{new_resource.version}") else - shell_out_compact_timeout!( "pkgrm", "-n", options, name ) + shell_out_compact!( "pkgrm", "-n", options, name ) logger.trace("#{new_resource} removed version #{new_resource.version}") end end diff --git a/lib/chef/provider/package/windows.rb b/lib/chef/provider/package/windows.rb index 8958bff068..05f865d4e4 100644 --- a/lib/chef/provider/package/windows.rb +++ b/lib/chef/provider/package/windows.rb @@ -44,6 +44,7 @@ class Chef requirements.assert(:install) do |a| a.assertion { ::File.exist?(new_resource.source) } a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.name} does not exist" + a.whyrun "Assuming source file #{new_resource.source} would have been created." end end end diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb index 1c18e4bfc4..325ffc9584 100644 --- a/lib/chef/provider/package/yum.rb +++ b/lib/chef/provider/package/yum.rb @@ -260,7 +260,7 @@ class Chef end def yum(*args) - shell_out_compact_timeout!(yum_binary, *args) + shell_out_compact!(yum_binary, *args) end def safe_version_array diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb index c2638fbfc1..5aa4ec7762 100644 --- a/lib/chef/provider/package/zypper.rb +++ b/lib/chef/provider/package/zypper.rb @@ -35,7 +35,7 @@ class Chef candidate_version = current_version = nil is_installed = false logger.trace("#{new_resource} checking zypper") - status = shell_out_compact_timeout!("zypper", "--non-interactive", "info", package_name) + status = shell_out_compact!("zypper", "--non-interactive", "info", package_name) status.stdout.each_line do |line| case line when /^Version *: (.+) *$/ @@ -86,7 +86,7 @@ class Chef def locked_packages @locked_packages ||= begin - locked = shell_out_compact_timeout!("zypper", "locks") + locked = shell_out_compact!("zypper", "locks") locked.stdout.each_line.map do |line| line.split("|").shift(2).last.strip end @@ -144,9 +144,9 @@ class Chef def zypper_package(command, *options, names, versions) zipped_names = zip(names, versions) if zypper_version < 1.0 - shell_out_compact_timeout!("zypper", gpg_checks, command, *options, "-y", names) + shell_out_compact!("zypper", gpg_checks, command, *options, "-y", names) else - shell_out_compact_timeout!("zypper", "--non-interactive", gpg_checks, command, *options, zipped_names) + shell_out_compact!("zypper", "--non-interactive", gpg_checks, command, *options, zipped_names) end end diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 05349b80e7..478637ff4e 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -1161,6 +1161,22 @@ class Chef end end + # Set or return if this resource is in preview mode. + # + # This is used in Chef core as part of the process of migrating resources + # from a cookbook into core. It should be set to `true` when a cookbook + # resource is added to core, and then removed (set to `false`) in the next + # major release. + # + # @param value [nil, Boolean] If nil, get the current value. If not nil, set + # the value of the flag. + # @return [Boolean] + def self.preview_resource(value = nil) + @preview_resource = false unless defined?(@preview_resource) + @preview_resource = value unless value.nil? + @preview_resource + end + # # Internal Resource Interface (for Chef) # @@ -1305,6 +1321,12 @@ class Chef remove_canonical_dsl end + # If a resource is in preview mode, set allow_cookbook_override on all its + # mappings by default. + if preview_resource && !options.include?(:allow_cookbook_override) + options[:allow_cookbook_override] = true + end + result = Chef.resource_handler_map.set(name, self, options, &block) Chef::DSL::Resources.add_resource_dsl(name) result diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb index d16355d027..234bbf8fd2 100644 --- a/lib/chef/resource/freebsd_package.rb +++ b/lib/chef/resource/freebsd_package.rb @@ -63,6 +63,8 @@ class Chef elsif supports_pkgng? Chef::Provider::Package::Freebsd::Pkgng else + Chef.deprecated(:freebsd_package_provider, "The freebsd_package provider for pkg (Chef::Provider::Package::Freebsd::Pkg) is deprecated and will be removed from Chef core in 15.0 (April 2019).") + Chef::Provider::Package::Freebsd::Pkg end end diff --git a/lib/chef/resource/kernel_module.rb b/lib/chef/resource/kernel_module.rb new file mode 100644 index 0000000000..bea56dedc2 --- /dev/null +++ b/lib/chef/resource/kernel_module.rb @@ -0,0 +1,129 @@ +# +# Resource:: kernel_module +# +# The MIT License (MIT) +# +# Copyright 2016-2018, Shopify Inc. +# Copyright 2018, Chef Software, Inc. + +require "chef/resource" + +class Chef + class Resource + class KernelModule < Chef::Resource + preview_resource true + resource_name :kernel_module + + description "Use the kernel_module resource to manage kernel modules on Linux systems. This resource can load, unload, blacklist, install, and uninstall modules." + introduced "14.3" + + property :modname, String, + description: "The name of the kernel module.", + name_property: true, identity: true + + property :load_dir, String, + description: "The directory to load modules from.", + default: "/etc/modules-load.d" + + property :unload_dir, String, + description: "The modprobe.d directory.", + default: "/etc/modprobe.d" + + action :install do + description "Load kernel module, and ensure it loads on reboot" + + # load the module first before installing + new_resource.run_action(:load) + + directory new_resource.load_dir do + recursive true + end + + file "#{new_resource.load_dir}/#{new_resource.modname}.conf" do + content "#{new_resource.modname}\n" + notifies :run, "execute[update initramfs]" + end + + execute "update initramfs" do + command initramfs_command + action :nothing + end + end + + action :uninstall do + description "Unload a kernel module and remove module config, so it doesn't load on reboot." + + file "#{new_resource.load_dir}/#{new_resource.modname}.conf" do + action :delete + notifies :run, "execute[update initramfs]" + end + + file "#{new_resource.unload_dir}/blacklist_#{new_resource.modname}.conf" do + action :delete + notifies :run, "execute[update initramfs]" + end + + execute "update initramfs" do + command initramfs_command + action :nothing + end + + new_resource.run_action(:unload) + end + + action :blacklist do + description "Blacklist a kernel module." + + file "#{new_resource.unload_dir}/blacklist_#{new_resource.modname}.conf" do + content "blacklist #{new_resource.modname}" + notifies :run, "execute[update initramfs]" + end + + execute "update initramfs" do + command initramfs_command + action :nothing + end + + new_resource.run_action(:unload) + end + + action :load do + description "Load a kernel module." + + unless module_loaded? + converge_by("load kernel module #{new_resource.modname}") do + shell_out!("modprobe #{new_resource.modname}") + end + end + end + + action :unload do + description "Unload kernel module" + + if module_loaded? + converge_by("unload kernel module #{new_resource.modname}") do + shell_out!("modprobe -r #{new_resource.modname}") + end + end + end + + action_class do + # determine the correct command to regen the initramfs based on platform + # @return [String] + def initramfs_command + if platform_family?("debian") + "update-initramfs -u" + else + "dracut -f" + end + end + + # see if the module is listed in /proc/modules or not + # @return [Boolean] + def module_loaded? + /^#{new_resource.modname}/.match?(::File.read("/proc/modules")) + end + end + end + end +end diff --git a/lib/chef/resource/paludis_package.rb b/lib/chef/resource/paludis_package.rb index 15378cd2e5..722163254f 100644 --- a/lib/chef/resource/paludis_package.rb +++ b/lib/chef/resource/paludis_package.rb @@ -1,6 +1,6 @@ # # Author:: Vasiliy Tolstov (<v.tolstov@selfip.ru>) -# Copyright:: Copyright 2014-2016, Chef Software Inc. +# Copyright:: Copyright 2014-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/chef/resource/portage_package.rb b/lib/chef/resource/portage_package.rb index 6936f5129f..43b0cfc74d 100644 --- a/lib/chef/resource/portage_package.rb +++ b/lib/chef/resource/portage_package.rb @@ -25,6 +25,8 @@ class Chef provides :portage_package description "Use the portage_package resource to manage packages for the Gentoo platform." + + property :timeout, default: 3600 end end end diff --git a/lib/chef/resource/powershell_package.rb b/lib/chef/resource/powershell_package.rb index 1056a8011c..ae6e410f21 100644 --- a/lib/chef/resource/powershell_package.rb +++ b/lib/chef/resource/powershell_package.rb @@ -37,7 +37,7 @@ class Chef property :package_name, [String, Array], coerce: proc { |x| [x].flatten } property :version, [String, Array], coerce: proc { |x| [x].flatten } property :source, [String] - property :skip_publisher_check, [true, false], default: false, introduced: "14.2", description: "Skip validating module author" + property :skip_publisher_check, [true, false], default: false, introduced: "14.3", description: "Skip validating module author" end end end diff --git a/lib/chef/resource/ssh_known_hosts_entry.rb b/lib/chef/resource/ssh_known_hosts_entry.rb new file mode 100644 index 0000000000..07e35587b7 --- /dev/null +++ b/lib/chef/resource/ssh_known_hosts_entry.rb @@ -0,0 +1,146 @@ +# +# Author:: Seth Vargo (<sethvargo@gmail.com>) +# +# Copyright:: 2013-2018, Seth Vargo +# Copyright:: 2017-2018, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require "chef/resource" + +class Chef + class Resource + class SshKnownHostsEntry < Chef::Resource + preview_resource true + resource_name :ssh_known_hosts_entry + + description "Use the ssh_known_hosts_entry resource to append an entry for the specified host in /etc/ssh/ssh_known_hosts or a user's known hosts file if specified." + introduced "14.3" + + property :host, String, + description: "The host to add to the known hosts file.", + name_property: true + + property :key, String, + description: "An optional key for the host. If not provided this will be automatically determined." + + property :key_type, String, + description: "The type of key to store.", + default: "rsa" + + property :port, Integer, + description: "The server port that the ssh-keyscan command will use to gather the public key.", + default: 22 + + property :timeout, Integer, + description: "The timeout in seconds for ssh-keyscan.", + default: 30 + + property :mode, String, + description: "The file mode for the ssh_known_hosts file.", + default: "0644" + + property :owner, String, + description: "The file owner for the ssh_known_hosts file.", + default: "root" + + property :group, String, + description: "The file group for the ssh_known_hosts file.", + default: lazy { node["root_group"] } + + property :hash_entries, [TrueClass, FalseClass], + description: "Hash the hostname and addresses in the ssh_known_hosts file for privacy.", + default: false + + property :file_location, String, + description: "The location of the ssh known hosts file. Change this to set a known host file for a particular user.", + default: "/etc/ssh/ssh_known_hosts" + + action :create do + description "Create an entry in the ssh_known_hosts file." + + key = + if new_resource.key + hoststr = (new_resource.port != 22) ? "[#{new_resource.host}]:#{new_resource.port}" : new_resource.host + "#{hoststr} #{type_string(new_resource.key_type)} #{new_resource.key}" + else + keyscan_cmd = ["ssh-keyscan", "-t#{new_resource.key_type}", "-p #{new_resource.port}"] + keyscan_cmd << "-H" if new_resource.hash_entries + keyscan_cmd << new_resource.host + keyscan = shell_out!(keyscan_cmd.join(" "), timeout: new_resource.timeout) + keyscan.stdout + end + + key.sub!(/^#{new_resource.host}/, "[#{new_resource.host}]:#{new_resource.port}") if new_resource.port != 22 + + comment = key.split("\n").first || "" + + r = with_run_context :root do + find_resource(:template, "update ssh known hosts file #{new_resource.file_location}") do + source ::File.expand_path("../support/ssh_known_hosts.erb", __FILE__) + local true + path new_resource.file_location + owner new_resource.owner + group new_resource.group + mode new_resource.mode + action :nothing + delayed_action :create + backup false + variables(entries: []) + end + end + + keys = r.variables[:entries].reject(&:empty?) + + if key_exists?(keys, key, comment) + Chef::Log.debug "Known hosts key for #{new_resource.name} already exists - skipping" + else + r.variables[:entries].push(key) + end + end + + # all this does is send an immediate run_action(:create) to the template resource + action :flush do + description "Immediately flush the entries to the config file. Without this the actual writing of the file is delayed in the Chef run so all entries can be accumulated before writing the file out." + + with_run_context :root do + # if you haven't ever called ssh_known_hosts_entry before you're definitely doing it wrong so we blow up hard. + find_resource!(:template, "update ssh known hosts file #{new_resource.file_location}").run_action(:create) + # it is the user's responsibility to only call this *after* all the ssh_known_hosts_entry resources have been called. + # if you call this too early in your run_list you will get a partial known_host file written to disk, and the resource + # behavior will not be idempotent (template resources will flap and never show 0 resources updated on converged boxes). + Chef::Log.warn "flushed ssh_known_hosts entries to file, later ssh_known_hosts_entry resources will not have been written" + end + end + + action_class do + def key_exists?(keys, key, comment) + keys.any? do |line| + line.match(/#{Regexp.escape(comment)}|#{Regexp.escape(key)}/) + end + end + + def type_string(key_type) + type_map = { + "rsa" => "ssh-rsa", + "dsa" => "ssh-dss", + "ecdsa" => "ecdsa-sha2-nistp256", + "ed25519" => "ssh-ed25519", + } + type_map[key_type] || key_type + end + end + end + end +end diff --git a/lib/chef/resource/support/ssh_known_hosts.erb b/lib/chef/resource/support/ssh_known_hosts.erb new file mode 100644 index 0000000000..0073b250ff --- /dev/null +++ b/lib/chef/resource/support/ssh_known_hosts.erb @@ -0,0 +1,3 @@ +<% @entries.sort.each do |entry| -%> +<%= entry %> +<% end -%> diff --git a/lib/chef/resource/windows_feature_dism.rb b/lib/chef/resource/windows_feature_dism.rb index ebd52c4db7..fc6f25fb3f 100644 --- a/lib/chef/resource/windows_feature_dism.rb +++ b/lib/chef/resource/windows_feature_dism.rb @@ -17,6 +17,7 @@ # require "chef/resource" +require "chef/platform/query_helpers" class Chef class Resource @@ -30,7 +31,7 @@ class Chef property :feature_name, [Array, String], description: "The name of the feature/role(s) to install if it differs from the resource name.", - coerce: proc { |x| to_lowercase_array(x) }, + coerce: proc { |x| to_formatted_array(x) }, name_property: true property :source, String, @@ -44,12 +45,12 @@ class Chef description: "Specifies a timeout (in seconds) for feature install.", default: 600 - def to_lowercase_array(x) + # @return [Array] lowercase the array unless we're on < Windows 2012 + def to_formatted_array(x) x = x.split(/\s*,\s*/) if x.is_a?(String) # split multiple forms of a comma separated list - # dism on windows < 2012 is case sensitive so only downcase when on 2012+ - # @todo when we're really ready to remove support for Windows 2008 R2 this check can go away - node["platform_version"].to_f < 6.2 ? x : x.map(&:downcase) + # feature installs on windows < 2012 are case sensitive so only downcase when on 2012+ + Chef::Platform.older_than_win_2012_or_8? ? x : x.map(&:downcase) end action :install do @@ -200,7 +201,7 @@ class Chef # dism on windows 2012+ isn't case sensitive so it's best to compare # lowercase lists so the user input doesn't need to be case sensitive # @todo when we're ready to remove windows 2008R2 the gating here can go away - feature_details.downcase! unless node["platform_version"].to_f < 6.2 + feature_details.downcase! unless Chef::Platform.older_than_win_2012_or_8? node.override["dism_features_cache"][feature_type] << feature_details end @@ -208,7 +209,7 @@ class Chef # @return [void] def fail_if_removed return if new_resource.source # if someone provides a source then all is well - if node["platform_version"].to_f > 6.2 + if node["platform_version"].to_f > 6.2 # 2012R2 or later return if registry_key_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing') && registry_value_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing', name: "LocalSourcePath") # if source is defined in the registry, still fine end removed = new_resource.feature_name & node["dism_features_cache"]["removed"] @@ -218,7 +219,7 @@ class Chef # Fail unless we're on windows 8+ / 2012+ where deleting a feature is supported # @return [void] def raise_if_delete_unsupported - raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not support on Windows releases before Windows 8/2012. Cannot continue!" unless node["platform_version"].to_f >= 6.2 + raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not supported on Windows releases before Windows 8/2012. Cannot continue!" if Chef::Platform.older_than_win_2012_or_8? end end end diff --git a/lib/chef/resource/windows_feature_powershell.rb b/lib/chef/resource/windows_feature_powershell.rb index 82713e3438..daee0e9d34 100644 --- a/lib/chef/resource/windows_feature_powershell.rb +++ b/lib/chef/resource/windows_feature_powershell.rb @@ -19,6 +19,7 @@ require "chef/mixin/powershell_out" require "chef/json_compat" require "chef/resource" +require "chef/platform/query_helpers" class Chef class Resource @@ -35,7 +36,7 @@ class Chef property :feature_name, [Array, String], description: "The name of the feature/role(s) to install if it differs from the resource name.", - coerce: proc { |x| to_lowercase_array(x) }, + coerce: proc { |x| to_formatted_array(x) }, name_property: true property :source, String, @@ -54,9 +55,13 @@ class Chef description: "", default: false - def to_lowercase_array(x) + # Converts strings of features into an Array. Array objects are lowercased unless we're on < 8/2k12+. + # @return [Array] array of features + def to_formatted_array(x) x = x.split(/\s*,\s*/) if x.is_a?(String) # split multiple forms of a comma separated list - x.map(&:downcase) + + # feature installs on windows < 8/2012 are case sensitive so only downcase when on 2012+ + Chef::Platform.older_than_win_2012_or_8? ? x : x.map(&:downcase) end include Chef::Mixin::PowershellOut @@ -73,8 +78,8 @@ class Chef converge_by("install Windows feature#{'s' if features_to_install.count > 1} #{features_to_install.join(',')}") do install_command = "#{install_feature_cmdlet} #{features_to_install.join(',')}" install_command << " -IncludeAllSubFeature" if new_resource.all - if node["platform_version"].to_f < 6.2 && (new_resource.source || new_resource.management_tools) - Chef::Log.warn("The 'source' and 'management_tools' properties are not available on Windows 2012R2 or great. Skipping these properties!") + if Chef::Platform.older_than_win_2012_or_8? && (new_resource.source || new_resource.management_tools) + Chef::Log.warn("The 'source' and 'management_tools' properties are only available on Windows 8/2012 or greater. Skipping these properties!") else install_command << " -Source \"#{new_resource.source}\"" if new_resource.source install_command << " -IncludeManagementTools" if new_resource.management_tools @@ -148,12 +153,16 @@ class Chef raise "The windows_feature_powershell resource requires PowerShell 3.0 or later. Please install PowerShell 3.0+ before running this resource." if powershell_version < 3 end + # The appropriate cmdlet to install a windows feature based on windows release + # @return [String] def install_feature_cmdlet - node["platform_version"].to_f < 6.2 ? "Import-Module ServerManager; Add-WindowsFeature" : "Install-WindowsFeature" + Chef::Platform.older_than_win_2012_or_8? ? "Add-WindowsFeature" : "Install-WindowsFeature" end + # The appropriate cmdlet to remove a windows feature based on windows release + # @return [String] def remove_feature_cmdlet - node["platform_version"].to_f < 6.2 ? "Import-Module ServerManager; Remove-WindowsFeature" : "Uninstall-WindowsFeature" + Chef::Platform.older_than_win_2012_or_8? ? "Remove-WindowsFeature" : "Uninstall-WindowsFeature" end # @return [Array] features the user has requested to install which need installation @@ -220,8 +229,9 @@ class Chef # fetch the list of available feature names and state in JSON and parse the JSON def parsed_feature_list # Grab raw feature information from dism command line - raw_list_of_features = if node["platform_version"].to_f < 6.2 - powershell_out!("Import-Module ServerManager; Get-WindowsFeature | Select-Object -Property Name,InstallState | ConvertTo-Json -Compress", timeout: new_resource.timeout).stdout + # Windows < 2012 doesn't present a state value so we have to check if the feature is installed or not + raw_list_of_features = if Chef::Platform.older_than_win_2012_or_8? # make the older format look like the new format, warts and all + powershell_out!('Get-WindowsFeature | Select-Object -Property Name, @{Name=\"InstallState\"; Expression = {If ($_.Installed) { 1 } Else { 0 }}} | ConvertTo-Json -Compress', timeout: new_resource.timeout).stdout else powershell_out!("Get-WindowsFeature | Select-Object -Property Name,InstallState | ConvertTo-Json -Compress", timeout: new_resource.timeout).stdout end @@ -232,14 +242,15 @@ class Chef # add the features values to the appropriate array # @return [void] def add_to_feature_mash(feature_type, feature_details) - node.override["powershell_features_cache"][feature_type] << feature_details.downcase # lowercase so we can compare properly + # add the lowercase feature name to the mash unless we're on < 2012 where they're case sensitive + node.override["powershell_features_cache"][feature_type] << (Chef::Platform.older_than_win_2012_or_8? ? feature_details : feature_details.downcase) end # Fail if any of the packages are in a removed state # @return [void] def fail_if_removed return if new_resource.source # if someone provides a source then all is well - if node["platform_version"].to_f > 6.2 + if node["platform_version"].to_f > 6.2 # 2012R2 or later return if registry_key_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing') && registry_value_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing', name: "LocalSourcePath") # if source is defined in the registry, still fine end removed = new_resource.feature_name & node["powershell_features_cache"]["removed"] @@ -248,7 +259,7 @@ class Chef # Fail unless we're on windows 8+ / 2012+ where deleting a feature is supported def raise_if_delete_unsupported - raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not support on Windows releases before Windows 8/2012. Cannot continue!" unless node["platform_version"].to_f >= 6.2 + raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not supported on Windows releases before Windows 8/2012. Cannot continue!" if Chef::Platform.older_than_win_2012_or_8? end end end diff --git a/lib/chef/resource_inspector.rb b/lib/chef/resource_inspector.rb index bbec03ffd6..10fa42c842 100644 --- a/lib/chef/resource_inspector.rb +++ b/lib/chef/resource_inspector.rb @@ -43,6 +43,7 @@ module ResourceInspector data[:actions] = resource.allowed_actions data[:examples] = resource.examples data[:introduced] = resource.introduced + data[:preview] = resource.preview_resource properties = unless complete resource.properties.reject { |_, k| k.options[:declared_in] == Chef::Resource } diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb index c232ce04e1..d942518b21 100644 --- a/lib/chef/resources.rb +++ b/lib/chef/resources.rb @@ -49,6 +49,7 @@ require "chef/resource/homebrew_cask" require "chef/resource/homebrew_package" require "chef/resource/homebrew_tap" require "chef/resource/ifconfig" +require "chef/resource/kernel_module" require "chef/resource/ksh" require "chef/resource/launchd" require "chef/resource/link" @@ -92,6 +93,7 @@ require "chef/resource/sudo" require "chef/resource/sysctl" require "chef/resource/swap_file" require "chef/resource/systemd_unit" +require "chef/resource/ssh_known_hosts_entry" require "chef/resource/windows_service" require "chef/resource/subversion" require "chef/resource/smartos_package" diff --git a/lib/chef/version.rb b/lib/chef/version.rb index 6b7512dda9..6e62f4a52b 100644 --- a/lib/chef/version.rb +++ b/lib/chef/version.rb @@ -23,7 +23,7 @@ require "chef/version_string" class Chef CHEF_ROOT = File.expand_path("../..", __FILE__) - VERSION = Chef::VersionString.new("14.2.2") + VERSION = Chef::VersionString.new("14.3.6") end # diff --git a/omnibus/resources/chef/msi/source.wxs.erb b/omnibus/resources/chef/msi/source.wxs.erb index c87c400624..f07050e13d 100644 --- a/omnibus/resources/chef/msi/source.wxs.erb +++ b/omnibus/resources/chef/msi/source.wxs.erb @@ -266,7 +266,7 @@ --> <Icon Id="oc.ico" SourceFile="Resources\assets\oc_16x16.ico"/> <Property Id="ARPPRODUCTICON" Value="oc.ico" /> - <Property Id="ARPHELPLINK" Value="http://www.getchef.com/support/" /> + <Property Id="ARPHELPLINK" Value="https://www.chef.io/support/" /> <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" /> <UIRef Id="ChefClientUI_InstallDir"/> diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb index 24f3bebe2a..7e4980219a 100644 --- a/spec/unit/node_map_spec.rb +++ b/spec/unit/node_map_spec.rb @@ -22,6 +22,12 @@ require "chef/node_map" class Foo; end class Bar; end +class FooResource < Chef::Resource; end +class BarResource < Chef::Resource; end + +class FooProvider < Chef::Provider; end +class BarProvider < Chef::Provider; end + describe Chef::NodeMap do let(:node_map) { Chef::NodeMap.new } @@ -139,14 +145,14 @@ describe Chef::NodeMap do describe "deleting classes" do it "deletes a class and removes the mapping completely" do node_map.set(:thing, Bar) - expect( node_map.delete_class(Bar) ).to eql({ :thing => [{ :klass => Bar }] }) + expect( node_map.delete_class(Bar) ).to include({ :thing => [{ :klass => Bar, :cookbook_override => false, :core_override => false }] }) expect( node_map.get(node, :thing) ).to eql(nil) end it "deletes a class and leaves the mapping that still has an entry" do node_map.set(:thing, Bar) node_map.set(:thing, Foo) - expect( node_map.delete_class(Bar) ).to eql({ :thing => [{ :klass => Bar }] }) + expect( node_map.delete_class(Bar) ).to eql({ :thing => [{ :klass => Bar, :cookbook_override => false, :core_override => false }] }) expect( node_map.get(node, :thing) ).to eql(Foo) end @@ -154,7 +160,7 @@ describe Chef::NodeMap do node_map.set(:thing1, Bar) node_map.set(:thing2, Bar) node_map.set(:thing2, Foo) - expect( node_map.delete_class(Bar) ).to eql({ :thing1 => [{ :klass => Bar }], :thing2 => [{ :klass => Bar }] }) + expect( node_map.delete_class(Bar) ).to eql({ :thing1 => [{ :klass => Bar, :cookbook_override => false, :core_override => false }], :thing2 => [{ :klass => Bar, :cookbook_override => false, :core_override => false }] }) expect( node_map.get(node, :thing1) ).to eql(nil) expect( node_map.get(node, :thing2) ).to eql(Foo) end @@ -204,4 +210,66 @@ describe Chef::NodeMap do end end + describe "locked mode" do + context "while unlocked" do + it "allows setting the same key twice" do + expect(Chef).to_not receive(:log_deprecation) + node_map.set(:foo, FooResource) + node_map.set(:foo, BarResource) + expect(node_map.get(node, :foo)).to eql(BarResource) + end + end + + context "while locked" do + # Uncomment the commented `expect`s in 15.0. + it "rejects setting the same key twice" do + expect(Chef).to receive(:log_deprecation).with("Trying to register resource foo on top of existing Chef core resource. Check if a new version of the cookbook is available.") + node_map.set(:foo, FooResource) + node_map.lock! + node_map.set(:foo, BarResource) + # expect(node_map.get(node, :foo)).to eql(FooResource) + end + + it "allows setting the same key twice when the first has allow_cookbook_override" do + expect(Chef).to_not receive(:log_deprecation) + node_map.set(:foo, FooResource, allow_cookbook_override: true) + node_map.lock! + node_map.set(:foo, BarResource) + expect(node_map.get(node, :foo)).to eql(BarResource) + end + + it "allows setting the same key twice when the first has allow_cookbook_override with a future version" do + expect(Chef).to_not receive(:log_deprecation) + node_map.set(:foo, FooResource, allow_cookbook_override: "< 100") + node_map.lock! + node_map.set(:foo, BarResource) + expect(node_map.get(node, :foo)).to eql(BarResource) + end + + it "rejects setting the same key twice when the first has allow_cookbook_override with a past version" do + expect(Chef).to receive(:log_deprecation).with("Trying to register resource foo on top of existing Chef core resource. Check if a new version of the cookbook is available.") + node_map.set(:foo, FooResource, allow_cookbook_override: "< 1") + node_map.lock! + node_map.set(:foo, BarResource) + # expect(node_map.get(node, :foo)).to eql(FooResource) + end + + it "allows setting the same key twice when the second has __core_override__" do + expect(Chef).to_not receive(:log_deprecation) + node_map.set(:foo, FooResource) + node_map.lock! + node_map.set(:foo, BarResource, __core_override__: true) + expect(node_map.get(node, :foo)).to eql(BarResource) + end + + it "rejects setting the same key twice for a provider" do + expect(Chef).to receive(:log_deprecation).with("Trying to register provider foo on top of existing Chef core provider. Check if a new version of the cookbook is available.") + node_map.set(:foo, FooProvider) + node_map.lock! + node_map.set(:foo, BarProvider) + # expect(node_map.get(node, :foo)).to eql(FooProvider) + end + end + end + end diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index 0700f69eb4..e132bc3d21 100644 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -415,7 +415,7 @@ mpg123 1.12.1-0ubuntu1 @provider.lock_package("irssi", "0.8.12-7") end it "should not lock if the package is already locked" do - allow(@provider).to receive(:shell_out_compact_timeout!).with( + allow(@provider).to receive(:shell_out_compact!).with( "apt-mark", "showhold" ).and_return(instance_double( Mixlib::ShellOut, stdout: "irssi") @@ -436,7 +436,7 @@ mpg123 1.12.1-0ubuntu1 @provider.unlock_package("irssi", "0.8.12-7") end it "should not unlock if the package is already unlocked" do - allow(@provider).to receive(:shell_out_compact_timeout!).with( + allow(@provider).to receive(:shell_out_compact!).with( "apt-mark", "showhold" ).and_return(instance_double( Mixlib::ShellOut, stdout: "") @@ -499,7 +499,7 @@ mpg123 1.12.1-0ubuntu1 it "should run dpkg to compare versions if an existing version is installed" do allow(@provider).to receive(:get_current_versions).and_return("1.4.0") allow(@new_resource).to receive(:allow_downgrade).and_return(false) - expect(@provider).to receive(:shell_out_compact_timeout).with( + expect(@provider).to receive(:shell_out_compact).with( "dpkg", "--compare-versions", "1.4.0", "gt", "0.8.12-7" ).and_return(double(error?: false)) @provider.run_action(:upgrade) diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb index e01e1d9cce..7c7c9c605e 100644 --- a/spec/unit/provider/package/dpkg_spec.rb +++ b/spec/unit/provider/package/dpkg_spec.rb @@ -207,7 +207,7 @@ Section: ruby it "should raise an exception if dpkg-deb -W fails to run" do status = double(:stdout => "", :exitstatus => -1) - expect(provider).to receive(:shell_out_compact_timeout!).with("dpkg-deb", "-W", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb").and_raise(Mixlib::ShellOut::ShellCommandFailed) + expect(provider).to receive(:shell_out_compact!).with("dpkg-deb", "-W", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb").and_raise(Mixlib::ShellOut::ShellCommandFailed) expect { provider.load_current_resource }.to raise_error(Mixlib::ShellOut::ShellCommandFailed) end end diff --git a/spec/unit/provider/package/paludis_spec.rb b/spec/unit/provider/package/paludis_spec.rb index df0150c8c0..fe3f5f61d7 100644 --- a/spec/unit/provider/package/paludis_spec.rb +++ b/spec/unit/provider/package/paludis_spec.rb @@ -1,6 +1,6 @@ # # Author:: Vasiliy Tolstov <v.tolstov@selfip.ru> -# Copyright:: Copyright 2014-2016, Chef Software Inc. +# Copyright:: Copyright 2014-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -59,7 +59,7 @@ PKG_STATUS end it "should run pkg info with the package name" do - expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "print-ids", "-M", "none", "-m", @new_resource.package_name, "-f", "%c/%p %v %r\n").and_return(@shell_out) + expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "print-ids", "-M", "none", "-m", @new_resource.package_name, "-f", "%c/%p %v %r\n", timeout: 900).and_return(@shell_out) @provider.load_current_resource end @@ -126,7 +126,7 @@ PKG_STATUS context "when uninstalling a package" do it "should run pkg uninstall with the package name and version" do - expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "uninstall", "-x", "=net/ntp-4.2.6_p5-r2") + expect(@provider).to receive(:shell_out!).with("cave", "-L", "warning", "uninstall", "-x", "=net/ntp-4.2.6_p5-r2", timeout: 900) @provider.remove_package("net/ntp", "4.2.6_p5-r2") end diff --git a/spec/unit/provider/package/portage_spec.rb b/spec/unit/provider/package/portage_spec.rb index 40dc44b113..5e971ba7e8 100644 --- a/spec/unit/provider/package/portage_spec.rb +++ b/spec/unit/provider/package/portage_spec.rb @@ -1,6 +1,6 @@ # # Author:: Caleb Tennis (<caleb.tennis@gmail.com>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. +# Copyright:: Copyright 2008-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,19 +22,19 @@ describe Chef::Provider::Package::Portage, "load_current_resource" do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Package.new("dev-util/git") - @new_resource_without_category = Chef::Resource::Package.new("git") - @current_resource = Chef::Resource::Package.new("dev-util/git") + @new_resource = Chef::Resource::PortagePackage.new("dev-util/git") + @new_resource_without_category = Chef::Resource::PortagePackage.new("git") + @current_resource = Chef::Resource::PortagePackage.new("dev-util/git") @provider = Chef::Provider::Package::Portage.new(@new_resource, @run_context) - allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource) + allow(Chef::Resource::PortagePackage).to receive(:new).and_return(@current_resource) end describe "when determining the current state of the package" do it "should create a current resource with the name of new_resource" do allow(::Dir).to receive(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0"]) - expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource) + expect(Chef::Resource::PortagePackage).to receive(:new).and_return(@current_resource) @provider.load_current_resource end @@ -148,17 +148,17 @@ EOF describe Chef::Provider::Package::Portage, "install_package" do it "should install a normally versioned package using portage" do - expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "=dev-util/git-1.0.0") + expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "=dev-util/git-1.0.0", timeout: 3600) @provider.install_package("dev-util/git", "1.0.0") end it "should install a tilde versioned package using portage" do - expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "~dev-util/git-1.0.0") + expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "~dev-util/git-1.0.0", timeout: 3600) @provider.install_package("dev-util/git", "~1.0.0") end it "should add options to the emerge command when specified" do - expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "--oneshot", "=dev-util/git-1.0.0") + expect(@provider).to receive(:shell_out!).with("emerge", "-g", "--color", "n", "--nospinner", "--quiet", "--oneshot", "=dev-util/git-1.0.0", timeout: 3600) @new_resource.options "--oneshot" @provider.install_package("dev-util/git", "1.0.0") end @@ -166,12 +166,12 @@ EOF describe Chef::Provider::Package::Portage, "remove_package" do it "should un-emerge the package with no version specified" do - expect(@provider).to receive(:shell_out!).with("emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", "dev-util/git") + expect(@provider).to receive(:shell_out!).with("emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", "dev-util/git", timeout: 3600) @provider.remove_package("dev-util/git", nil) end it "should un-emerge the package with a version specified" do - expect(@provider).to receive(:shell_out!).with("emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", "=dev-util/git-1.0.0") + expect(@provider).to receive(:shell_out!).with("emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", "=dev-util/git-1.0.0", timeout: 3600) @provider.remove_package("dev-util/git", "1.0.0") end end diff --git a/spec/unit/provider/package/windows_spec.rb b/spec/unit/provider/package/windows_spec.rb index 0f4fd465c8..aed0ca88be 100644 --- a/spec/unit/provider/package/windows_spec.rb +++ b/spec/unit/provider/package/windows_spec.rb @@ -398,13 +398,20 @@ describe Chef::Provider::Package::Windows, :windows_only do context "a missing local file is given" do let(:resource_source) { "C:/a_missing_file.exe" } let(:installer_type) { nil } - - it "raises a Package error" do + before do allow(::File).to receive(:exist?).with(provider.new_resource.source).and_return(false) - provider.load_current_resource + end + + it "raises a Package error" do expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) end + + it "why_run mode doesn't raise an error" do + Chef::Config[:why_run] = true + expect { provider.run_action(:install) }.not_to raise_error + Chef::Config[:why_run] = false + end end end diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb index 819278a795..756ba3a480 100644 --- a/spec/unit/provider/package/zypper_spec.rb +++ b/spec/unit/provider/package/zypper_spec.rb @@ -270,10 +270,10 @@ describe Chef::Provider::Package::Zypper do describe "action_lock" do it "should lock if the package is not already locked" do prov = provider - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "--non-interactive", "info", new_resource.package_name ).and_return(status) - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "locks" ).and_return(instance_double( Mixlib::ShellOut, stdout: "1 | somethingelse | package | (any)" @@ -286,10 +286,10 @@ describe Chef::Provider::Package::Zypper do it "should not lock if the package is already locked" do prov = provider - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "--non-interactive", "info", new_resource.package_name ).and_return(status) - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "locks" ).and_return(instance_double( Mixlib::ShellOut, stdout: "1 | cups | package | (any)" @@ -327,10 +327,10 @@ describe Chef::Provider::Package::Zypper do describe "action_unlock" do it "should unlock if the package is not already unlocked" do prov = provider - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "--non-interactive", "info", new_resource.package_name ).and_return(status) - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "locks" ).and_return(instance_double( Mixlib::ShellOut, stdout: "1 | cups | package | (any)" @@ -342,10 +342,10 @@ describe Chef::Provider::Package::Zypper do end it "should not unlock if the package is already unlocked" do prov = provider - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "--non-interactive", "info", new_resource.package_name ).and_return(status) - allow(prov).to receive(:shell_out_compact_timeout!).with( + allow(prov).to receive(:shell_out_compact!).with( "zypper", "locks" ).and_return(instance_double( Mixlib::ShellOut, stdout: "1 | somethingelse | package | (any)" diff --git a/spec/unit/resource/freebsd_package_spec.rb b/spec/unit/resource/freebsd_package_spec.rb index b609284895..9747c41a88 100644 --- a/spec/unit/resource/freebsd_package_spec.rb +++ b/spec/unit/resource/freebsd_package_spec.rb @@ -93,6 +93,7 @@ describe Chef::Resource::FreebsdPackage do [1000016, 1000000, 901503, 902506, 802511].each do |freebsd_version| node.automatic_attrs[:os_version] = freebsd_version + expect(Chef).to receive(:deprecated).with(:freebsd_package_provider, kind_of(String)) resource.after_created expect(resource.provider).to eq(Chef::Provider::Package::Freebsd::Pkg) end diff --git a/spec/unit/resource/kernel_module_spec.rb b/spec/unit/resource/kernel_module_spec.rb new file mode 100644 index 0000000000..03cda28471 --- /dev/null +++ b/spec/unit/resource/kernel_module_spec.rb @@ -0,0 +1,48 @@ +# +# Copyright:: Copyright 2018, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" + +describe Chef::Resource::KernelModule do + let(:resource) { Chef::Resource::KernelModule.new("foo") } + + it "sets resource name as :kernel_module" do + expect(resource.resource_name).to eql(:kernel_module) + end + + it "is not a preview resource in Chef 15" do + pending("Chef 15") unless Chef::VERSION.start_with?("15") + expect(resource.class.preview_resource).to be_falsey + end + + it "sets the default action as :install" do + expect(resource.action).to eql([:install]) + end + + it "sets the modname property as its name property" do + expect(resource.modname).to eql("foo") + end + + it "supports :create and :flush actions" do + expect { resource.action :install }.not_to raise_error + expect { resource.action :uninstall }.not_to raise_error + expect { resource.action :blacklist }.not_to raise_error + expect { resource.action :load }.not_to raise_error + expect { resource.action :unload }.not_to raise_error + expect { resource.action :delete }.to raise_error(ArgumentError) + end +end diff --git a/spec/unit/resource/ssh_known_hosts_entry_spec.rb b/spec/unit/resource/ssh_known_hosts_entry_spec.rb new file mode 100644 index 0000000000..3bae37dfe7 --- /dev/null +++ b/spec/unit/resource/ssh_known_hosts_entry_spec.rb @@ -0,0 +1,55 @@ +# +# Copyright:: Copyright 2018, Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "spec_helper" + +describe Chef::Resource::SshKnownHostsEntry do + let(:node) { Chef::Node.new } + let(:run_context) do + node.automatic[:root_group] = "superduper" + empty_events = Chef::EventDispatch::Dispatcher.new + Chef::RunContext.new(node, {}, empty_events) + end + let(:resource) { Chef::Resource::SshKnownHostsEntry.new("example.com", run_context) } + + it "is not a preview resource in Chef 15" do + pending("Chef 15") unless Chef::VERSION.start_with?("15") + expect(resource.class.preview_resource).to be_falsey + end + + it "sets resource name as :ssh_known_hosts_entry" do + expect(resource.resource_name).to eql(:ssh_known_hosts_entry) + end + + it "sets group property to node['root_group'] by default" do + expect(resource.group).to eql("superduper") + end + + it "sets the default action as :create" do + expect(resource.action).to eql([:create]) + end + + it "sets the host property as its name property" do + expect(resource.host).to eql("example.com") + end + + it "supports :create and :flush actions" do + expect { resource.action :create }.not_to raise_error + expect { resource.action :flush }.not_to raise_error + expect { resource.action :delete }.to raise_error(ArgumentError) + end +end diff --git a/spec/unit/resource/windows_feature_dism.rb b/spec/unit/resource/windows_feature_dism.rb index 4627387ddb..87d99ecbaf 100644 --- a/spec/unit/resource/windows_feature_dism.rb +++ b/spec/unit/resource/windows_feature_dism.rb @@ -32,7 +32,7 @@ describe Chef::Resource::WindowsFeatureDism do end it "the feature_name property is the name_property" do - node.automatic[:platform_version] = "6.2" + node.automatic[:platform_version] = "6.2.9200" expect(resource.feature_name).to eql(%w{snmp dhcp}) end @@ -47,25 +47,25 @@ describe Chef::Resource::WindowsFeatureDism do end it "coerces comma separated lists of features to a lowercase array on 2012+" do - node.automatic[:platform_version] = "6.2" + node.automatic[:platform_version] = "6.2.9200" resource.feature_name "SNMP, DHCP" expect(resource.feature_name).to eql(%w{snmp dhcp}) end it "coerces a single feature as a String to a lowercase array on 2012+" do - node.automatic[:platform_version] = "6.2" + node.automatic[:platform_version] = "6.2.9200" resource.feature_name "SNMP" expect(resource.feature_name).to eql(["snmp"]) end it "coerces comma separated lists of features to an array, but preserves case on < 2012" do - node.automatic[:platform_version] = "6.1" + node.automatic[:platform_version] = "6.1.7601" resource.feature_name "SNMP, DHCP" expect(resource.feature_name).to eql(%w{SNMP DHCP}) end it "coerces a single feature as a String to an array, but preserves case on < 2012" do - node.automatic[:platform_version] = "6.1" + node.automatic[:platform_version] = "6.1.7601" resource.feature_name "SNMP" expect(resource.feature_name).to eql(["SNMP"]) end diff --git a/spec/unit/resource/windows_feature_powershell.rb b/spec/unit/resource/windows_feature_powershell.rb index a9b6f5f88f..3dc1604361 100644 --- a/spec/unit/resource/windows_feature_powershell.rb +++ b/spec/unit/resource/windows_feature_powershell.rb @@ -18,7 +18,10 @@ require "spec_helper" describe Chef::Resource::WindowsFeaturePowershell do - let(:resource) { Chef::Resource::WindowsFeaturePowershell.new(%w{SNMP DHCP}) } + let(:node) { Chef::Node.new } + let(:events) { Chef::EventDispatch::Dispatcher.new } + let(:run_context) { Chef::RunContext.new(node, {}, events) } + let(:resource) { Chef::Resource::WindowsFeaturePowershell.new(%w{SNMP DHCP}, run_context) } it "sets resource name as :windows_feature_powershell" do expect(resource.resource_name).to eql(:windows_feature_powershell) @@ -28,24 +31,42 @@ describe Chef::Resource::WindowsFeaturePowershell do expect(resource.action).to eql([:install]) end + it "the feature_name property is the name_property" do + node.automatic[:platform_version] = "6.2.9200" + expect(resource.feature_name).to eql(%w{snmp dhcp}) + end + + it "sets the default action as :install" do + expect(resource.action).to eql([:install]) + end + it "supports :delete, :install, :remove actions" do expect { resource.action :delete }.not_to raise_error expect { resource.action :install }.not_to raise_error expect { resource.action :remove }.not_to raise_error end - it "sets the feature_name property as its name_property" do - expect(resource.feature_name).to eql(%w{SNMP DHCP}) + it "coerces comma separated lists of features to a lowercase array on 2012+" do + node.automatic[:platform_version] = "6.2.9200" + resource.feature_name "SNMP, DHCP" + expect(resource.feature_name).to eql(%w{snmp dhcp}) + end + + it "coerces a single feature as a String to a lowercase array on 2012+" do + node.automatic[:platform_version] = "6.2.9200" + resource.feature_name "SNMP" + expect(resource.feature_name).to eql(["snmp"]) end - it "coerces comma separated lists of features to arrays" do + it "coerces comma separated lists of features to an array, but preserves case on < 2012" do + node.automatic[:platform_version] = "6.1.7601" resource.feature_name "SNMP, DHCP" expect(resource.feature_name).to eql(%w{SNMP DHCP}) end - it "coerces a single feature as a String into an array" do + it "coerces a single feature as a String to an array, but preserves case on < 2012" do + node.automatic[:platform_version] = "6.1.7601" resource.feature_name "SNMP" expect(resource.feature_name).to eql(["SNMP"]) end - end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 2866d5439f..26660c9415 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -867,7 +867,7 @@ end snitch_var1 = snitch_var2 = 0 runner = Chef::Runner.new(run_context) - Chef::Provider::SnakeOil.provides :cat + Chef::Provider::SnakeOil.provides :cat, __core_override__: true resource1.only_if { snitch_var1 = 1 } resource1.not_if { snitch_var2 = 2 } @@ -1144,4 +1144,38 @@ end it { is_expected.to eq [:two, :one] } end end + + describe ".preview_resource" do + let(:klass) { Class.new(Chef::Resource) } + + before do + allow(Chef::DSL::Resources).to receive(:add_resource_dsl).with(:test_resource) + end + + it "defaults to false" do + expect(klass.preview_resource).to eq false + end + + it "can be set to true" do + klass.preview_resource(true) + expect(klass.preview_resource).to eq true + end + + it "does not affect provides by default" do + expect(Chef.resource_handler_map).to receive(:set).with(:test_resource, klass, { canonical: true }) + klass.resource_name(:test_resource) + end + + it "adds allow_cookbook_override when true" do + expect(Chef.resource_handler_map).to receive(:set).with(:test_resource, klass, { canonical: true, allow_cookbook_override: true }) + klass.preview_resource(true) + klass.resource_name(:test_resource) + end + + it "allows manually overriding back to false" do + expect(Chef.resource_handler_map).to receive(:set).with(:test_resource, klass, { allow_cookbook_override: false }) + klass.preview_resource(true) + klass.provides(:test_resource, allow_cookbook_override: false) + end + end end |