diff options
Diffstat (limited to 'lib/chef')
80 files changed, 1219 insertions, 637 deletions
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb index bfea51609a..95b03f1c5c 100644 --- a/lib/chef/chef_class.rb +++ b/lib/chef/chef_class.rb @@ -200,13 +200,14 @@ class Chef # # Emit a deprecation message. # - # @param [Symbol] type The message to send. This should refer to a class + # @param type [Symbol] The message to send. This should refer to a class # defined in Chef::Deprecated - # @param message An explicit message to display, rather than the generic one - # associated with the deprecation. - # @param location The location. Defaults to the caller who called you (since - # generally the person who triggered the check is the one that needs to be - # fixed). + # @param message [String, nil] An explicit message to display, rather than + # the generic one associated with the deprecation. + # @param location [String, nil] The location. Defaults to the caller who + # called you (since generally the person who triggered the check is the one + # that needs to be fixed). + # @return [void] # # @example # Chef.deprecated(:my_deprecation, message: "This is deprecated!") @@ -220,11 +221,18 @@ class Chef # run. If we are not yet in a run, print to `Chef::Log`. if run_context && run_context.events run_context.events.deprecation(deprecation, location) - else - Chef::Log.deprecation(deprecation, location) + elsif !deprecation.silenced? + Chef::Log.deprecation(deprecation.to_s) end end + # Log a generic deprecation warning that doesn't have a specific class in + # Chef::Deprecated. + # + # This should generally not be used, as the user will not be given a link + # to get more infomration on fixing the deprecation warning. + # + # @see #deprecated def log_deprecation(message, location = nil) location ||= Chef::Log.caller_location Chef.deprecated(:generic, message, location) 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..d9a8df7b83 100644 --- a/lib/chef/deprecated.rb +++ b/lib/chef/deprecated.rb @@ -24,266 +24,196 @@ class Chef class << self include Chef::Mixin::ConvertToClassName - def create(type, message = nil, location = nil) - Chef::Deprecated.const_get(convert_to_class_name(type.to_s)).send(:new, message, location) + def create(type, message, location) + Chef::Deprecated.const_get(convert_to_class_name(type.to_s)).new(message, location) end end class Base BASE_URL = "https://docs.chef.io/deprecations_" - attr_accessor :message, :location + attr_reader :message, :location def initialize(msg = nil, location = nil) - @message = msg if msg - @location = location if location + @message = msg + @location = location end def link "Please see #{url} for further details and information on how to correct this problem." end + # Render the URL for the deprecation documentation page. + # + # @return [String] def url - "#{BASE_URL}#{target}" - end - - # We know that the only time this gets called is by Chef::Log.deprecation, - # so special case - def <<(location) - @location = location - end - - def inspect - "#{message} (CHEF-#{id})#{location}.\n#{link}" - end - - def id - raise NotImplementedError, "subclasses of Chef::Deprecated::Base should define #id with a unique number" - end - - def target - raise NotImplementedError, "subclasses of Chef::Deprecated::Base should define #target" + "#{BASE_URL}#{self.class.doc_page}" + end + + # Render the user-visible message for this deprecation. + # + # @return [String] + def to_s + "Deprecation CHEF-#{self.class.deprecation_id} from #{location}\n\n #{message}\n\n#{link}" + end + + # Check if this deprecation has been silenced. + # + # @return [Boolean] + def silenced? + # Check if all warnings have been silenced. + return true if Chef::Config[:silence_deprecation_warnings] == true + # Check if this warning has been silenced by the config. + return true if Chef::Config[:silence_deprecation_warnings].any? do |silence_spec| + # Just in case someone uses a symbol in the config by mistake. + silence_spec = silence_spec.to_s + # Check for a silence by deprecation name, or by location. + self.class.deprecation_key == silence_spec || self.class.deprecation_id.to_s == silence_spec || "chef-#{self.class.deprecation_id}" == silence_spec.downcase || location.include?(silence_spec) + end + # check if this warning has been silenced by inline comment. + return true if location =~ /^(.*?):(\d+):in/ && begin + # Don't buffer the whole file in memory, so read it one line at a time. + line_no = $2.to_i + location_file = ::File.open($1) + (line_no - 1).times { location_file.readline } # Read all the lines we don't care about. + relevant_line = location_file.readline + relevant_line.match?(/#.*chef:silence_deprecation($|[^:]|:#{self.class.deprecation_key})/) + end + false + end + + class << self + attr_reader :deprecation_id, :doc_page + + # Return the deprecation key as would be used with {Chef::Deprecated.create}. + # + # @return [String] + def deprecation_key + Chef::Mixin::ConvertToClassName.convert_to_snake_case(name, "Chef::Deprecated") + end + + # Set the ID and documentation page path for this deprecation. + # + # Used in subclasses to set the data for each type of deprecation. + # + # @example + # class MyDeprecation < Base + # target 123, "my_deprecation.html" + # end + # @param id [Integer] Deprecation ID number. This must be unique among + # all deprecations. + # @param page [String, nil] Optional documentation page path. If not + # specified, the deprecation key is used. + # @return [void] + def target(id, page = nil) + @deprecation_id = id + @doc_page = page || "#{deprecation_key}.html" + end end end class InternalApi < Base - def id - 0 - end - - def target - "internal_api.html" - end + target 0 end class JsonAutoInflate < Base - def id - 1 - end - - def target - "json_auto_inflate.html" - end + target 1 end class ExitCode < Base - def id - 2 - end - - def target - "exit_code.html" - end + target 2 end # id 3 has been deleted class Attributes < Base - def id - 4 - end - - def target - "attributes.html" - end + target 4 end class CustomResource < Base - def id - 5 - end - - def target - "custom_resource_cleanups.html" - end + target 5, "custom_resource_cleanups.html" end class EasyInstall < Base - def id - 6 - end - - def target - "easy_install.html" - end + target 6 end class VerifyFile < Base - def id - 7 - end - - def target - "verify_file.html" - end + target 7 end class SupportsProperty < Base - def id - 8 - end - - def target - "supports_property.html" - end + target 8 end class ChefRest < Base - def id - 9 - end - - def target - "chef_rest.html" - end + target 9 end class DnfPackageAllowDowngrade < Base - def id - 10 - end - - def target - "dnf_package_allow_downgrade.html" - end + target 10 end class PropertyNameCollision < Base - def id - 11 - end - - def target - "property_name_collision.html" - end + target 11 end class LaunchdHashProperty < Base - def id - 12 - end - - def target - "launchd_hash_property.html" - end + target 12 end class ChefPlatformMethods < Base - def id - 13 - end - - def target - "chef_platform_methods.html" - end + target 13 end class RunCommand < Base - def id - 14 - end - - def target - "run_command.html" - end + target 14 end class PackageMisc < Base - def id - 15 - end - - def target - "package_misc.html" - end + target 15 end class MultiresourceMatch < Base - def id - 16 - end - - def target - "multiresource_match.html" - end + target 16 end class UseInlineResources < Base - def id - 17 - end - - def target - "use_inline_resources.html" - end + target 17 end class LocalListen < Base - def id - 18 - end - - def target - "local_listen.html" - end + target 18 end class NamespaceCollisions < Base - def id - 19 - end - - def target - "namespace_collisions.html" - end + target 19 end class DeployResource < Base - def id - 21 - end - - def target - "deploy_resource.html" - end + target 21 end class ErlResource < Base - def id - 22 - end + target 22 + end - def target - "erl_resource.html" - end + class FreebsdPkgProvider < Base + target 23 + end + + class MapCollision < Base + target 25 end # id 3694 was deleted # Returned when using the deprecated option on a property class Property < Base - def inspect - "#{message}\n#{location}" + target 24 + + def to_s + "Deprecated resource property used from #{location}\n\n #{message}\n\nPlease consult the resource documentation for more information." end end @@ -292,8 +222,8 @@ class Chef "https://docs.chef.io/chef_deprecations_client.html" end - def inspect - "#{message}\nThis is a generic error message and should be updated to have a proper deprecation class. #{location}\nPlease see #{url} for an overview of Chef deprecations." + def to_s + "Deprecation from #{location}\n\n #{message}\n\n#{link}" end end diff --git a/lib/chef/formatters/base.rb b/lib/chef/formatters/base.rb index 0b27b55048..997577aa7b 100644 --- a/lib/chef/formatters/base.rb +++ b/lib/chef/formatters/base.rb @@ -212,14 +212,13 @@ class Chef file_load_failed(path, exception) end - def deprecation(message, location = caller(2..2)[0]) - out = if is_structured_deprecation?(message) - message.inspect - else - "#{message} at #{location}" - end - - Chef::Log.deprecation(out) + # Log a deprecation warning object. + # + # @param deprecation [Chef::Deprecated::Base] Deprecation object to log. + # In previous versions, this could be a string. Don't do that anymore. + # @param location [Object] Unused, present only for compatbility. + def deprecation(deprecation, _location = nil) + Chef::Log.deprecation(deprecation.to_s) unless deprecation.silenced? end def is_structured_deprecation?(deprecation) diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb index 0c51cc2cfb..d47ab73a30 100644 --- a/lib/chef/formatters/doc.rb +++ b/lib/chef/formatters/doc.rb @@ -414,19 +414,15 @@ class Chef end end - def deprecation(message, location = caller(2..2)[0]) + # (see Base#deprecation) + def deprecation(deprecation, _location = nil) if Chef::Config[:treat_deprecation_warnings_as_errors] super + elsif !deprecation.silenced? + # Save non-silenced deprecations to the screen until the end. + deprecations[deprecation.message] ||= { url: deprecation.url, locations: Set.new } + deprecations[deprecation.message][:locations] << deprecation.location end - - # Save deprecations to the screen until the end - if is_structured_deprecation?(message) - url = message.url - message = message.message - end - - deprecations[message] ||= { url: url, locations: Set.new } - deprecations[message][:locations] << location end def indent diff --git a/lib/chef/log.rb b/lib/chef/log.rb index 10c9f0f20d..3f77158579 100644 --- a/lib/chef/log.rb +++ b/lib/chef/log.rb @@ -46,19 +46,21 @@ class Chef # def self.caller_location # Pick the first caller that is *not* part of the Chef gem, that's the - # thing the user wrote. + # thing the user wrote. Or failing that, the most recent caller. chef_gem_path = File.expand_path("../..", __FILE__) - caller(0..20).find { |c| !c.start_with?(chef_gem_path) } + caller(0..20).find { |c| !c.start_with?(chef_gem_path) } || caller(0..1)[0] end - def self.deprecation(msg = nil, location = caller(2..2)[0], &block) - if msg - msg << " at #{Array(location).join("\n")}" - msg = msg.join("") if msg.respond_to?(:join) - end + # Log a deprecation warning. + # + # If the treat_deprecation_warnings_as_errors config option is set, this + # will raise an exception instead. + # + # @param msg [String] Deprecation message to display. + def self.deprecation(msg, &block) if Chef::Config[:treat_deprecation_warnings_as_errors] error(msg, &block) - raise Chef::Exceptions::DeprecatedFeatureError.new(msg.inspect) + raise Chef::Exceptions::DeprecatedFeatureError.new(msg) else warn(msg, &block) end diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb index 236ef844b1..2c67d34630 100644 --- a/lib/chef/mixin/shell_out.rb +++ b/lib/chef/mixin/shell_out.rb @@ -21,89 +21,126 @@ require "chef/mixin/path_sanity" class Chef module Mixin module ShellOut - include Chef::Mixin::PathSanity + extend Chef::Mixin::PathSanity # PREFERRED APIS: # - # shell_out_compact and shell_out_compact! flatten their array arguments and remove nils and pass - # the resultant array to shell_out. this actually eliminates spaces-in-args bugs because this: + # all consumers should now call shell_out!/shell_out. # - # shell_out!("command #{arg}") + # on unix the shell_out API supports the clean_array() kind of syntax (below) so that + # array args are flat/compact/to_s'd. on windows, array args aren't supported to its + # up to the caller to join(" ") on arrays of strings. # - # becomes two arguments if arg has spaces and requires quotations: + # the shell_out_compacted/shell_out_compacted! APIs are private but are intended for use + # in rspec tests, and should ideally always be used to make code refactorings that do not + # change behavior easier: # - # shell_out!("command '#{arg}'") + # allow(provider).to receive(:shell_out_compacted!).with("foo", "bar", "baz") + # provider.shell_out!("foo", [ "bar", nil, "baz"]) + # provider.shell_out!(["foo", nil, "bar" ], ["baz"]) # - # using shell_out_compact! this becomes: - # - # shell_out_compact!("command", arg) - # - # and spaces in the arg just works and it does not become two arguments (and the shell quoting around - # the argument must actually be removed). - # - # there's also an implicit join between all the array elements, and nested arrays are flattened which - # means that odd where-do-i-put-the-spaces options handling just works, and instead of this: - # - # opts = "" # needs to be empty string for when foo and bar are both missing - # opts << " -foo" if needs_foo? # needs the leading space on both of these - # opts << " -bar" if needs_bar? - # shell_out!("cmd#{opts}") # have to think way too hard about why there's no space here - # - # becomes: - # - # opts = [] - # opts << "-foo" if needs_foo? - # opts << "-bar" if needs_bar? - # shell_out_compact!("cmd", opts) - # - # and opts can be an empty array or nil and it'll work out fine. - # - # generally its best to use shell_out_compact! in code and setup expectations on shell_out! in tests + # note that shell_out_compacted also includes adding the magical timeout option to force + # people to setup expectations on that value explicitly. it does not include the default_env + # mangling in order to avoid users having to setup an expectation on anything other than + # setting `default_env: false` and allow us to make tweak to the default_env without breaking + # a thousand unit tests. # - def shell_out_compact(*args, **options) + def shell_out_compact(*args, **options) # FIXME: deprecate if options.empty? - shell_out(*clean_array(*args)) + shell_out(*args) else - shell_out(*clean_array(*args), **options) + shell_out(*args, **options) end end - def shell_out_compact!(*args, **options) + def shell_out_compact!(*args, **options) # FIXME: deprecate if options.empty? - shell_out!(*clean_array(*args)) + shell_out!(*args) else - shell_out!(*clean_array(*args), **options) + shell_out!(*args, **options) end end - # helper sugar for resources that support passing timeouts to shell_out + def shell_out_compact_timeout(*args, **options) # FIXME: deprecate + if options.empty? + shell_out(*args) + else + shell_out(*args, **options) + end + end + + def shell_out_compact_timeout!(*args, **options) # FIXME: deprecate + if options.empty? + shell_out!(*args) + else + shell_out!(*args, **options) + end + 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) + def shell_out_with_systems_locale(*args, **options) # FIXME: deprecate + if options.empty? + shell_out(*args, default_env: false) + else + shell_out(*args, default_env: false, **options) + end 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) + def shell_out_with_systems_locale!(*args, **options) # FIXME: deprecate + if options.empty? + shell_out!(*args, default_env: false) + else + shell_out!(*args, default_env: false, **options) + end end - # shell_out! runs a command on the system and will raise an error if the command fails, which is what you want - # for debugging, shell_out and shell_out! both will display command output to the tty when the log level is debug - # Generally speaking, 'extend Chef::Mixin::ShellOut' in your recipes and include 'Chef::Mixin::ShellOut' in your LWRPs - # You can also call Mixlib::Shellout.new directly, but you lose all of the above functionality + def a_to_s(*args) # FIXME: deprecate + # can't quite deprecate this yet + #Chef.deprecated(:package_misc, "a_to_s is deprecated use shell_out_compact or shell_out_compact_timeout instead") + args.flatten.reject { |i| i.nil? || i == "" }.map(&:to_s).join(" ") + end - # we use 'en_US.UTF-8' by default because we parse localized strings in English as an API and - # generally must support UTF-8 unicode. def shell_out(*args, **options) options = options.dup + options = Chef::Mixin::ShellOut.maybe_add_timeout(self, options) + if options.empty? + shell_out_compacted(*Chef::Mixin::ShellOut.clean_array(*args)) + else + shell_out_compacted(*Chef::Mixin::ShellOut.clean_array(*args), **options) + end + end + + def shell_out!(*args, **options) + options = options.dup + options = Chef::Mixin::ShellOut.maybe_add_timeout(self, options) + if options.empty? + shell_out_compacted!(*Chef::Mixin::ShellOut.clean_array(*args)) + else + shell_out_compacted!(*Chef::Mixin::ShellOut.clean_array(*args), **options) + end + 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) + # note that we can't define an empty Chef::Resource::LWRPBase because that breaks descendants tracker, so we'd have to instead require the file here, which would pull in half + # of chef, so instead convert to using strings. once descendants tracker is gone, we can just declare the empty classes instead and use `is_a?` against the symbols. + # (be nice if ruby supported strings in `is_a?` for looser coupling). + if obj.class.ancestors.map(&:to_s).include?("Chef::Provider") && !obj.class.ancestors.map(&:to_s).include?("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 + + # helper function to mangle options when `default_env` is true + # + # @api private + def self.apply_default_env(options) + options = options.dup default_env = options.delete(:default_env) default_env = true if default_env.nil? if default_env @@ -115,34 +152,37 @@ class Chef env_path => sanitized_path, }.update(options[env_key] || {}) end - shell_out_command(*args, **options) + options end - # call shell_out (using en_US.UTF-8) and raise errors - def shell_out!(*command_args) - cmd = shell_out(*command_args) - cmd.error! - cmd - end - - def shell_out_with_systems_locale(*args, **options) # FIXME: deprecate - shell_out(*args, default_env: false, **options) - end + private - def shell_out_with_systems_locale!(*args, **options) # FIXME: deprecate - shell_out!(*args, default_env: false, **options) + # this SHOULD be used for setting up expectations in rspec, see banner comment at top. + # + # the private constraint is meant to avoid code calling this directly, rspec expectations are fine. + # + def shell_out_compacted(*args, **options) + options = Chef::Mixin::ShellOut.apply_default_env(options) + if options.empty? + Chef::Mixin::ShellOut.shell_out_command(*args) + else + Chef::Mixin::ShellOut.shell_out_command(*args, **options) + end end - # Helper for subclasses to convert an array of string args into a string. It - # will compact nil or empty strings in the array and will join the array elements - # with spaces, without introducing any double spaces for nil/empty elements. + # this SHOULD be used for setting up expectations in rspec, see banner comment at top. # - # @param args [String] variable number of string arguments - # @return [String] nicely concatenated string or empty string - def a_to_s(*args) - # can't quite deprecate this yet - #Chef.deprecated(:package_misc, "a_to_s is deprecated use shell_out_compact or shell_out_compact_timeout instead") - args.flatten.reject { |i| i.nil? || i == "" }.map(&:to_s).join(" ") + # the private constraint is meant to avoid code calling this directly, rspec expectations are fine. + # + def shell_out_compacted!(*args, **options) + options = Chef::Mixin::ShellOut.apply_default_env(options) + cmd = if options.empty? + Chef::Mixin::ShellOut.shell_out_command(*args) + else + Chef::Mixin::ShellOut.shell_out_command(*args, **options) + end + cmd.error! + cmd end # Helper for subclasses to reject nil out of an array. It allows @@ -161,20 +201,23 @@ class Chef # # @param args [String] variable number of string arguments # @return [Array] array of strings with nil and null string rejection - def clean_array(*args) + + def self.clean_array(*args) args.flatten.compact.map(&:to_s) end - private - - def shell_out_command(*command_args) - cmd = Mixlib::ShellOut.new(*command_args) + def self.shell_out_command(*args, **options) + cmd = if options.empty? + Mixlib::ShellOut.new(*args) + else + Mixlib::ShellOut.new(*args, **options) + end cmd.live_stream ||= io_for_live_stream cmd.run_command cmd end - def io_for_live_stream + def self.io_for_live_stream if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.debug? STDOUT else @@ -182,7 +225,7 @@ class Chef end end - def env_path + def self.env_path if Chef::Platform.windows? "Path" else diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb index 0406b3c1d6..c0066bfce5 100644 --- a/lib/chef/node_map.rb +++ b/lib/chef/node_map.rb @@ -37,6 +37,21 @@ # class Chef class NodeMap + COLLISION_WARNING_14 = <<-EOH.gsub(/\s+/, " ").strip +%{type_caps} %{key} has been loaded from a cookbook. The %{type} %{key} is now +included in Chef and will take precedence over the existing cookbook %{type} in the +next major release of Chef (15.0, April 2019). You may be able to remove this cookbook dependency from +your runlist if you do not use other recipes/resources/libraries from the cookbook. +Alternatively there may be a newer version of this cookbook without the %{key} %{type}. +EOH + + COLLISION_WARNING_15 = <<-EOH.gsub(/\s+/, " ").strip +%{type_caps} %{key} attempted to load from a cookbook. The %{type} %{key} is now +included in Chef and takes precedence over the existing cookbook %{type} +which will be ignored. You may be able to remove this cookbook dependency from +your runlist if you do not use other recipes/resources/libraries from the cookbook. +Alternatively there may be a newer version of this cookbook without the %{key} %{type}. +EOH # # Set a key/value pair on the map with a filter. The filter must be true @@ -45,12 +60,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 +80,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.deprecated(:map_collision, COLLISION_WARNING_14 % { type: type_of_thing, key: key, type_caps: type_of_thing.capitalize }) + # In 15.0, uncomment this and remove the log above. + # Chef.deprecated(:map_collision, COLLISION_WARNING_15 % {type: type_of_thing, key: key, type_caps: type_of_thing.capitalize})) + # 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 +205,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/group/aix.rb b/lib/chef/provider/group/aix.rb index 5c500e2753..7da07b8006 100644 --- a/lib/chef/provider/group/aix.rb +++ b/lib/chef/provider/group/aix.rb @@ -32,33 +32,33 @@ class Chef end def create_group - shell_out_compact!("mkgroup", set_options, new_resource.group_name) + shell_out!("mkgroup", set_options, new_resource.group_name) modify_group_members end def manage_group options = set_options if options.size > 0 - shell_out_compact!("chgroup", options, new_resource.group_name) + shell_out!("chgroup", options, new_resource.group_name) end modify_group_members end def remove_group - shell_out_compact!("rmgroup", new_resource.group_name) + shell_out!("rmgroup", new_resource.group_name) end def add_member(member) - shell_out_compact!("chgrpmem", "-m", "+", member, new_resource.group_name) + shell_out!("chgrpmem", "-m", "+", member, new_resource.group_name) end def set_members(members) return if members.empty? - shell_out_compact!("chgrpmem", "-m", "=", members.join(","), new_resource.group_name) + shell_out!("chgrpmem", "-m", "=", members.join(","), new_resource.group_name) end def remove_member(member) - shell_out_compact!("chgrpmem", "-m", "-", member, new_resource.group_name) + shell_out!("chgrpmem", "-m", "-", member, new_resource.group_name) end def set_options diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb index 81c7d66aa8..a5c4d27ddb 100644 --- a/lib/chef/provider/group/dscl.rb +++ b/lib/chef/provider/group/dscl.rb @@ -27,7 +27,7 @@ class Chef argdup = args.dup cmd = argdup.shift shellcmd = [ "dscl", ".", "-#{cmd}", argdup ] - status = shell_out_compact(shellcmd) + status = shell_out(shellcmd) stdout_result = "" stderr_result = "" status.stdout.each_line { |line| stdout_result << line } diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb index d8aff10d5b..a5d6a378c0 100644 --- a/lib/chef/provider/group/gpasswd.rb +++ b/lib/chef/provider/group/gpasswd.rb @@ -39,18 +39,18 @@ class Chef def set_members(members) if members.empty? - shell_out_compact!("gpasswd", "-M", "", new_resource.group_name) + shell_out!("gpasswd", "-M", "", new_resource.group_name) else - shell_out_compact!("gpasswd", "-M", members.join(","), new_resource.group_name) + shell_out!("gpasswd", "-M", members.join(","), new_resource.group_name) end end def add_member(member) - shell_out_compact!("gpasswd", "-a", member, new_resource.group_name) + shell_out!("gpasswd", "-a", member, new_resource.group_name) end def remove_member(member) - shell_out_compact!("gpasswd", "-d", member, new_resource.group_name) + shell_out!("gpasswd", "-d", member, new_resource.group_name) end end end diff --git a/lib/chef/provider/group/groupadd.rb b/lib/chef/provider/group/groupadd.rb index 7d7fac146c..fb8f306034 100644 --- a/lib/chef/provider/group/groupadd.rb +++ b/lib/chef/provider/group/groupadd.rb @@ -44,19 +44,19 @@ class Chef # Create the group def create_group - shell_out_compact!("groupadd", set_options, groupadd_options) + shell_out!("groupadd", set_options, groupadd_options) modify_group_members end # Manage the group when it already exists def manage_group - shell_out_compact!("groupmod", set_options) + shell_out!("groupmod", set_options) modify_group_members end # Remove the group def remove_group - shell_out_compact!("groupdel", new_resource.group_name) + shell_out!("groupdel", new_resource.group_name) end def modify_group_members diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb index 13f83db4c4..ac033e607d 100644 --- a/lib/chef/provider/group/groupmod.rb +++ b/lib/chef/provider/group/groupmod.rb @@ -32,7 +32,7 @@ class Chef # Create the group def create_group - shell_out_compact!("group", "add", set_options) + shell_out!("group", "add", set_options) add_group_members(new_resource.members) end @@ -79,14 +79,14 @@ class Chef # Remove the group def remove_group - shell_out_compact!("group", "del", new_resource.group_name) + shell_out!("group", "del", new_resource.group_name) end # Adds a list of usernames to the group using `user mod` def add_group_members(members) logger.trace("#{new_resource} adding members #{members.join(', ')}") unless members.empty? members.each do |user| - shell_out_compact!("user", "mod", "-G", new_resource.group_name, user) + shell_out!("user", "mod", "-G", new_resource.group_name, user) end end @@ -94,11 +94,11 @@ class Chef # "<name>_bak", create a new group with the same GID and # "<name>", then set correct members on that group def reset_group_membership - shell_out_compact!("group", "mod", "-n", "#{new_resource.group_name}_bak", new_resource.group_name) + shell_out!("group", "mod", "-n", "#{new_resource.group_name}_bak", new_resource.group_name) - shell_out_compact!("group", "add", set_options(overwrite_gid: true)) + shell_out!("group", "add", set_options(overwrite_gid: true)) - shell_out_compact!("group", "del", "#{new_resource.group_name}_bak") + shell_out!("group", "del", "#{new_resource.group_name}_bak") end # Little bit of magic as per Adam's useradd provider to pull and assign the command line flags diff --git a/lib/chef/provider/group/pw.rb b/lib/chef/provider/group/pw.rb index b0393a147e..2a1f294bde 100644 --- a/lib/chef/provider/group/pw.rb +++ b/lib/chef/provider/group/pw.rb @@ -48,24 +48,24 @@ class Chef command += [ "-M", new_resource.members.join(",") ] end - shell_out_compact!(command) + shell_out!(command) end # Manage the group when it already exists def manage_group member_options = set_members_options if member_options.empty? - shell_out_compact!("pw", "groupmod", set_options) + shell_out!("pw", "groupmod", set_options) else member_options.each do |option| - shell_out_compact!("pw", "groupmod", set_options, option) + shell_out!("pw", "groupmod", set_options, option) end end end # Remove the group def remove_group - shell_out_compact!("pw", "groupdel", new_resource.group_name) + shell_out!("pw", "groupdel", new_resource.group_name) end # Little bit of magic as per Adam's useradd provider to pull and assign the command line flags diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb index 0790d2c2d9..7e8473c901 100644 --- a/lib/chef/provider/group/suse.rb +++ b/lib/chef/provider/group/suse.rb @@ -66,7 +66,7 @@ class Chef end def add_member(member) - shell_out_compact!("groupmod", "-A", member, new_resource.group_name) + shell_out!("groupmod", "-A", member, new_resource.group_name) end def to_remove(members) @@ -74,7 +74,7 @@ class Chef end def remove_member(member) - shell_out_compact!("groupmod", "-R", member, new_resource.group_name) + shell_out!("groupmod", "-R", member, new_resource.group_name) end end diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb index 3874f7b4de..6b040b7190 100644 --- a/lib/chef/provider/group/usermod.rb +++ b/lib/chef/provider/group/usermod.rb @@ -66,7 +66,7 @@ class Chef end def add_member(member) - shell_out_compact!("usermod", append_flags, new_resource.group_name, member) + shell_out!("usermod", append_flags, new_resource.group_name, member) end def remove_member(member) diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb index 243c8ee9c3..f3d65d7c7c 100644 --- a/lib/chef/provider/ifconfig.rb +++ b/lib/chef/provider/ifconfig.rb @@ -163,7 +163,7 @@ class Chef unless new_resource.device == loopback_device command = add_command converge_by("run #{command.join(' ')} to add #{new_resource}") do - shell_out_compact!(command) + shell_out!(command) logger.info("#{new_resource} added") end end @@ -179,7 +179,7 @@ class Chef return if new_resource.device == loopback_device command = enable_command converge_by("run #{command.join(' ')} to enable #{new_resource}") do - shell_out_compact!(command) + shell_out!(command) logger.info("#{new_resource} enabled") end end @@ -189,7 +189,7 @@ class Chef if current_resource.device command = delete_command converge_by("run #{command.join(' ')} to delete #{new_resource}") do - shell_out_compact!(command) + shell_out!(command) logger.info("#{new_resource} deleted") end else @@ -204,7 +204,7 @@ class Chef if current_resource.device command = disable_command converge_by("run #{command.join(' ')} to disable #{new_resource}") do - shell_out_compact!(command) + shell_out!(command) logger.info("#{new_resource} disabled") end else diff --git a/lib/chef/provider/ifconfig/aix.rb b/lib/chef/provider/ifconfig/aix.rb index b68c5d5364..f9ecc1f22e 100644 --- a/lib/chef/provider/ifconfig/aix.rb +++ b/lib/chef/provider/ifconfig/aix.rb @@ -31,7 +31,7 @@ class Chef found_interface = false interface = {} - @status = shell_out_compact("ifconfig", "-a") + @status = shell_out("ifconfig", "-a") @status.stdout.each_line do |line| if !found_interface if line =~ /^(\S+):\sflags=(\S+)/ diff --git a/lib/chef/provider/mount/windows.rb b/lib/chef/provider/mount/windows.rb index 1bd932729d..590b2bfa52 100644 --- a/lib/chef/provider/mount/windows.rb +++ b/lib/chef/provider/mount/windows.rb @@ -40,9 +40,9 @@ class Chef def load_current_resource if is_volume(@new_resource.device) - @mount = Chef::Util::Windows::Volume.new(@new_resource.name) + @mount = Chef::Util::Windows::Volume.new(@new_resource.mount_point) else #assume network drive - @mount = Chef::Util::Windows::NetUse.new(@new_resource.name) + @mount = Chef::Util::Windows::NetUse.new(@new_resource.mount_point) end @current_resource = Chef::Resource::Mount.new(@new_resource.name) diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index 133f87dad9..ddd2fa5dd6 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 instead") if options " #{options.is_a?(Array) ? Shellwords.join(options) : options}" else @@ -668,17 +668,17 @@ class Chef end end - def shell_out_with_timeout(*command_args) + def shell_out_with_timeout(*command_args) # FIXME: deprecated shell_out(*add_timeout_option(command_args)) end - def shell_out_with_timeout!(*command_args) + def shell_out_with_timeout!(*command_args) # FIXME: deprecated shell_out!(*add_timeout_option(command_args)) end 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 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..f245e481a3 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!("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("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("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!(*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..652fad447b 100644 --- a/lib/chef/provider/package/bff.rb +++ b/lib/chef/provider/package/bff.rb @@ -34,11 +34,11 @@ class Chef super requirements.assert(:install) do |a| a.assertion { new_resource.source } - a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.name} required for action install" + a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.package_name} required for action install" end requirements.assert(:all_actions) do |a| a.assertion { !new_resource.source || package_source_found? } - a.failure_message Chef::Exceptions::Package, "Package #{new_resource.name} not found: #{new_resource.source}" + a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}" a.whyrun "would assume #{new_resource.source} would be have previously been made available" end end @@ -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("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("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("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!("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!("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!("installp", "-u", name) logger.trace("#{new_resource} removed version #{new_resource.version}") else - shell_out_compact_timeout!("installp", "-u", options, name) + shell_out!("installp", "-u", options, name) logger.trace("#{new_resource} removed version #{new_resource.version}") end end diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb index a6abdd5b46..c60483d0dc 100644 --- a/lib/chef/provider/package/chocolatey.rb +++ b/lib/chef/provider/package/chocolatey.rb @@ -171,7 +171,7 @@ EOS # @param args [String] variable number of string arguments # @return [Mixlib::ShellOut] object returned from shell_out! def choco_command(*args) - shell_out_with_timeout!(args_to_string(choco_exe, *args), returns: new_resource.returns) + shell_out!(args_to_string(choco_exe, *args), returns: new_resource.returns) end # Use the available_packages Hash helper to create an array suitable for diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb index b18a284116..2339b4cabe 100644 --- a/lib/chef/provider/package/dnf.rb +++ b/lib/chef/provider/package/dnf.rb @@ -121,7 +121,7 @@ class Chef private def resolve_source_to_version_obj - shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line| + shell_out!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line| # this is another case of committing the sin of doing some lightweight mangling of RPM versions in ruby -- but the output of the rpm command # does not match what the dnf library accepts. case line @@ -167,7 +167,7 @@ class Chef end def dnf(*args) - shell_out_compact_timeout!("dnf", *args) + shell_out!("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..de5b2858e7 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("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("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!("dpkg", "-s", package_name, returns: [0, 1]) package_installed = false status.stdout.each_line do |line| case line @@ -149,10 +149,10 @@ class Chef end end - # Runs command via shell_out_with_timeout with magic environment to disable + # Runs command via shell_out with magic environment to disable # interactive prompts. def run_noninteractive(*command) - shell_out_compact_timeout!(*command, env: { "DEBIAN_FRONTEND" => "noninteractive" }) + shell_out!(*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!("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..bf704a5cae 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!("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!("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..c847ae5658 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!("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!("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!("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!("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!("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!("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..250baf0fac 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!("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!("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!("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!("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!("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..7a46bbaf97 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!("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!("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!("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!("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..1a7407486b 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!(*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..f7fdb95e4d 100644 --- a/lib/chef/provider/package/ips.rb +++ b/lib/chef/provider/package/ips.rb @@ -1,7 +1,7 @@ # # Author:: Jason J. W. Williams (<williamsjj@digitar.com>) # Author:: Stephen Nelson-Smith (<sns@chef.io>) -# Copyright:: Copyright 2011-2017, Chef Software Inc. +# Copyright:: Copyright 2011-2018, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -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("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!("pkg", "info", "-r", new_resource.package_name).stdout.each_line do |line| return $1.split[0] if line =~ /Version: (.*)/ end nil @@ -58,7 +58,7 @@ class Chef def load_current_resource @current_resource = Chef::Resource::IpsPackage.new(new_resource.name) current_resource.package_name(new_resource.package_name) - logger.trace("Checking package status for #{new_resource.name}") + logger.trace("Checking package status for #{new_resource.package_name}") current_resource.version(get_current_version) @candidate_version = get_candidate_version current_resource @@ -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!(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!( "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..384435778d 100644 --- a/lib/chef/provider/package/macports.rb +++ b/lib/chef/provider/package/macports.rb @@ -16,7 +16,7 @@ class Chef @candidate_version = macports_candidate_version if !new_resource.version && !@candidate_version - raise Chef::Exceptions::Package, "Could not get a candidate version for this package -- #{new_resource.name} does not seem to be a valid package!" + raise Chef::Exceptions::Package, "Could not get a candidate version for this package -- #{new_resource.package_name} does not seem to be a valid package!" end logger.trace("#{new_resource} candidate version is #{@candidate_version}") if @candidate_version @@ -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!(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!(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!(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!( "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(command) begin output = status.stdout rescue Exception diff --git a/lib/chef/provider/package/msu.rb b/lib/chef/provider/package/msu.rb index c4e53a0fdf..9dbea31c82 100644 --- a/lib/chef/provider/package/msu.rb +++ b/lib/chef/provider/package/msu.rb @@ -125,7 +125,7 @@ class Chef def extract_msu_contents(msu_file, destination) with_os_architecture(nil) do - shell_out_with_timeout!("#{ENV['SYSTEMROOT']}\\system32\\expand.exe -f:* #{msu_file} #{destination}") + shell_out!("#{ENV['SYSTEMROOT']}\\system32\\expand.exe -f:* #{msu_file} #{destination}") end end diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb index f528c48f08..3408aef944 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!("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!("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!("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!("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 @@ -116,7 +116,7 @@ class Chef when 1 results[0] else - raise Chef::Exceptions::Package, "#{new_resource.name} has multiple matching candidates. Please use a more specific name" if results.length > 1 + raise Chef::Exceptions::Package, "#{new_resource.package_name} has multiple matching candidates. Please use a more specific name" if results.length > 1 end end end diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb index f6dde66219..4a3b795700 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("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("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!( "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!( "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..3550b155d5 100644 --- a/lib/chef/provider/package/paludis.rb +++ b/lib/chef/provider/package/paludis.rb @@ -35,7 +35,7 @@ class Chef installed = false re = Regexp.new("(.*)[[:blank:]](.*)[[:blank:]](.*)$") - shell_out_compact!("cave", "-L", "warning", "print-ids", "-M", "none", "-m", new_resource.package_name, "-f", "%c/%p %v %r\n").stdout.each_line do |line| + shell_out!("cave", "-L", "warning", "print-ids", "-M", "none", "-m", new_resource.package_name, "-f", "%c/%p %v %r\n").stdout.each_line do |line| res = re.match(line) next if res.nil? case res[3] @@ -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!("cave", "-L", "warning", "resolve", "-x", options, pkg) end def upgrade_package(name, version) @@ -72,7 +72,7 @@ class Chef new_resource.package_name.to_s end - shell_out_compact!("cave", "-L", "warning", "uninstall", "-x", options, pkg) + shell_out!("cave", "-L", "warning", "uninstall", "-x", options, pkg) end def purge_package(name, version) diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb index fecbba9dc9..11cbe99d18 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] @@ -66,7 +66,7 @@ class Chef def candidate_version return @candidate_version if @candidate_version - pkginfo = shell_out_compact("portageq", "best_visible", "/", new_resource.package_name) + pkginfo = shell_out("portageq", "best_visible", "/", new_resource.package_name) if pkginfo.exitstatus != 0 pkginfo.stderr.each_line do |line| @@ -106,7 +106,7 @@ class Chef pkg = "~#{name}-#{$1}" end - shell_out_compact!( "emerge", "-g", "--color", "n", "--nospinner", "--quiet", options, pkg ) + shell_out!( "emerge", "-g", "--color", "n", "--nospinner", "--quiet", options, pkg ) end def upgrade_package(name, version) @@ -120,7 +120,7 @@ class Chef new_resource.package_name.to_s end - shell_out_compact!( "emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", options, pkg ) + shell_out!( "emerge", "--unmerge", "--color", "n", "--nospinner", "--quiet", options, pkg ) end def purge_package(name, version) diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb index 9d4f2f3c23..3d070cee17 100644 --- a/lib/chef/provider/package/rpm.rb +++ b/lib/chef/provider/package/rpm.rb @@ -33,13 +33,13 @@ class Chef requirements.assert(:all_actions) do |a| a.assertion { @package_source_exists } - a.failure_message Chef::Exceptions::Package, "Package #{new_resource.name} not found: #{new_resource.source}" - a.whyrun "Assuming package #{new_resource.name} would have been made available." + a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}" + a.whyrun "Assuming package #{new_resource.package_name} would have been made available." end requirements.assert(:all_actions) do |a| a.assertion { !@rpm_status.nil? && (@rpm_status.exitstatus == 0 || @rpm_status.exitstatus == 1) } a.failure_message Chef::Exceptions::Package, "Unable to determine current version due to RPM failure. Detail: #{@rpm_status.inspect}" - a.whyrun "Assuming current version would have been determined for package#{new_resource.name}." + a.whyrun "Assuming current version would have been determined for package #{new_resource.package_name}." end end @@ -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!("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("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!("rpm", options, "-U", "--oldpackage", new_resource.source) else - shell_out_compact_timeout!("rpm", options, "-U", new_resource.source) + shell_out!("rpm", options, "-U", new_resource.source) end else - shell_out_compact_timeout!("rpm", options, "-i", new_resource.source) + shell_out!("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!("rpm", options, "-e", "#{name}-#{version}") else - shell_out_compact_timeout!("rpm", options, "-e", name) + shell_out!("rpm", options, "-e", name) end end diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb index 6b04af547b..d99dce8972 100644 --- a/lib/chef/provider/package/rubygems.rb +++ b/lib/chef/provider/package/rubygems.rb @@ -547,9 +547,9 @@ class Chef end src_str = src.empty? ? "" : " #{src.join(" ")}" if !version.nil? && !version.empty? - shell_out_with_timeout!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src_str}#{opts}", env: nil) + shell_out!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src_str}#{opts}", env: nil) else - shell_out_with_timeout!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src_str}#{opts}", env: nil) + shell_out!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src_str}#{opts}", env: nil) end end @@ -573,9 +573,9 @@ class Chef def uninstall_via_gem_command(name, version) if version - shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -v \"#{version}\"#{opts}", env: nil) + shell_out!("#{gem_binary_path} uninstall #{name} -q -x -I -v \"#{version}\"#{opts}", env: nil) else - shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -a#{opts}", env: nil) + shell_out!("#{gem_binary_path} uninstall #{name} -q -x -I -a#{opts}", env: nil) end end diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb index 5c637814a6..4623196c13 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!("/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!("/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!("/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!("/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..01958df1ee 100644 --- a/lib/chef/provider/package/solaris.rb +++ b/lib/chef/provider/package/solaris.rb @@ -38,11 +38,11 @@ class Chef super requirements.assert(:install) do |a| a.assertion { new_resource.source } - a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.name} required for action install" + a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.package_name} required for action install" end requirements.assert(:all_actions) do |a| a.assertion { !new_resource.source || @package_source_found } - a.failure_message Chef::Exceptions::Package, "Package #{new_resource.name} not found: #{new_resource.source}" + a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}" a.whyrun "would assume #{new_resource.source} would be have previously been made available" end end @@ -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("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("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("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!(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!(*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!( "pkgrm", "-n", name ) logger.trace("#{new_resource} removed version #{new_resource.version}") else - shell_out_compact_timeout!( "pkgrm", "-n", options, name ) + shell_out!( "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..d203adafe2 100644 --- a/lib/chef/provider/package/windows.rb +++ b/lib/chef/provider/package/windows.rb @@ -37,13 +37,14 @@ class Chef def define_resource_requirements requirements.assert(:install) do |a| a.assertion { new_resource.source || msi? } - a.failure_message Chef::Exceptions::NoWindowsPackageSource, "Source for package #{new_resource.name} must be specified in the resource's source property for package to be installed because the package_name property is used to test for the package installation state for this package type." + a.failure_message Chef::Exceptions::NoWindowsPackageSource, "Source for package #{new_resource.package_name} must be specified in the resource's source property for package to be installed because the package_name property is used to test for the package installation state for this package type." end unless uri_scheme?(new_resource.source) 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.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.package_name} does not exist" + a.whyrun "Assuming source file #{new_resource.source} would have been created." end end end @@ -120,7 +121,7 @@ class Chef if basename == "setup.exe" :installshield else - raise Chef::Exceptions::CannotDetermineWindowsInstallerType, "Installer type for Windows Package '#{new_resource.name}' not specified and cannot be determined from file extension '#{file_extension}'" + raise Chef::Exceptions::CannotDetermineWindowsInstallerType, "Installer type for Windows Package '#{new_resource.package_name}' not specified and cannot be determined from file extension '#{file_extension}'" end end end diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb index 1c18e4bfc4..42dd11b43f 100644 --- a/lib/chef/provider/package/yum.rb +++ b/lib/chef/provider/package/yum.rb @@ -210,7 +210,7 @@ class Chef end def resolve_source_to_version_obj - shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line| + shell_out!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line| # this is another case of committing the sin of doing some lightweight mangling of RPM versions in ruby -- but the output of the rpm command # does not match what the yum library accepts. case line @@ -260,7 +260,7 @@ class Chef end def yum(*args) - shell_out_compact_timeout!(yum_binary, *args) + shell_out!(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..058fcf1a6b 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!("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!("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!("zypper", gpg_checks, command, *options, "-y", names) else - shell_out_compact_timeout!("zypper", "--non-interactive", gpg_checks, command, *options, zipped_names) + shell_out!("zypper", "--non-interactive", gpg_checks, command, *options, zipped_names) end end diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb index b23d0307cc..2195abfe29 100644 --- a/lib/chef/provider/route.rb +++ b/lib/chef/provider/route.rb @@ -133,7 +133,7 @@ class Chef else command = generate_command(:add) converge_by("run #{command.join(' ')} to add route") do - shell_out_compact!(command) + shell_out!(command) logger.info("#{new_resource} added") end end @@ -146,7 +146,7 @@ class Chef if is_running command = generate_command(:delete) converge_by("run #{command.join(' ')} to delete route ") do - shell_out_compact!(command) + shell_out!(command) logger.info("#{new_resource} removed") end else diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb index 3270deb781..9bfcbb1410 100644 --- a/lib/chef/provider/service/simple.rb +++ b/lib/chef/provider/service/simple.rb @@ -163,6 +163,7 @@ class Chef end def ps_cmd + # XXX: magic attributes are a shitty api, need something better here and deprecate this attribute @run_context.node[:command] && @run_context.node[:command][:ps] end end diff --git a/lib/chef/provider/user/aix.rb b/lib/chef/provider/user/aix.rb index be6ff9d750..aca0511e41 100644 --- a/lib/chef/provider/user/aix.rb +++ b/lib/chef/provider/user/aix.rb @@ -24,7 +24,7 @@ class Chef provides :aix_user def create_user - shell_out_compact!("useradd", universal_options, useradd_options, new_resource.username) + shell_out!("useradd", universal_options, useradd_options, new_resource.username) add_password end @@ -32,11 +32,11 @@ class Chef add_password manage_home return if universal_options.empty? && usermod_options.empty? - shell_out_compact!("usermod", universal_options, usermod_options, new_resource.username) + shell_out!("usermod", universal_options, usermod_options, new_resource.username) end def remove_user - shell_out_compact!("userdel", userdel_options, new_resource.username) + shell_out!("userdel", userdel_options, new_resource.username) end # Aix does not support -r like other unix, sytem account is created by adding to 'system' group @@ -66,7 +66,7 @@ class Chef end def check_lock - lock_info = shell_out_compact!("lsuser", "-a", "account_locked", new_resource.username) + lock_info = shell_out!("lsuser", "-a", "account_locked", new_resource.username) if whyrun_mode? && passwd_s.stdout.empty? && lock_info.stderr.match(/does not exist/) # if we're in whyrun mode and the user is not yet created we assume it would be return false @@ -85,11 +85,11 @@ class Chef end def lock_user - shell_out_compact!("chuser", "account_locked=true", new_resource.username) + shell_out!("chuser", "account_locked=true", new_resource.username) end def unlock_user - shell_out_compact!("chuser", "account_locked=false", new_resource.username) + shell_out!("chuser", "account_locked=false", new_resource.username) end def universal_options diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb index 67fe8f3762..c22329d0d6 100644 --- a/lib/chef/provider/user/dscl.rb +++ b/lib/chef/provider/user/dscl.rb @@ -326,7 +326,7 @@ user password using shadow hash.") end def ditto_home - shell_out_compact!("/usr/sbin/createhomedir", "-c", "-u", "#{new_resource.username}") + shell_out!("/usr/sbin/createhomedir", "-c", "-u", "#{new_resource.username}") end def move_home @@ -364,7 +364,7 @@ user password using shadow hash.") # Shadow info is saved as binary plist. Convert the info to binary plist. shadow_info_binary = StringIO.new - shell_out_compact("plutil", "-convert", "binary1", "-o", "-", "-", + shell_out("plutil", "-convert", "binary1", "-o", "-", "-", input: shadow_info.to_plist, live_stream: shadow_info_binary) if user_info.nil? @@ -586,7 +586,7 @@ user password using shadow hash.") # We flush the cache here in order to make sure that we read fresh information # for the user. - shell_out_compact("dscacheutil", "-flushcache") # FIXME: this is MacOS version dependent + shell_out("dscacheutil", "-flushcache") # FIXME: this is MacOS version dependent begin user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist" @@ -654,7 +654,7 @@ user password using shadow hash.") end def run_dscl(*args) - result = shell_out_compact("dscl", ".", "-#{args[0]}", args[1..-1]) + result = shell_out("dscl", ".", "-#{args[0]}", args[1..-1]) return "" if ( args.first =~ /^delete/ ) && ( result.exitstatus != 0 ) raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") unless result.exitstatus == 0 raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") if result.stdout =~ /No such key: / @@ -662,7 +662,7 @@ user password using shadow hash.") end def run_plutil(*args) - result = shell_out_compact("plutil", "-#{args[0]}", args[1..-1]) + result = shell_out("plutil", "-#{args[0]}", args[1..-1]) raise(Chef::Exceptions::PlistUtilCommandFailed, "plutil error: #{result.inspect}") unless result.exitstatus == 0 if result.stdout.encoding == Encoding::ASCII_8BIT result.stdout.encode("utf-8", "binary", undef: :replace, invalid: :replace, replace: "?") @@ -672,7 +672,7 @@ user password using shadow hash.") end def convert_binary_plist_to_xml(binary_plist_string) - shell_out_compact("plutil", "-convert", "xml1", "-o", "-", "-", input: binary_plist_string).stdout + shell_out("plutil", "-convert", "xml1", "-o", "-", "-", input: binary_plist_string).stdout end def convert_to_binary(string) diff --git a/lib/chef/provider/user/linux.rb b/lib/chef/provider/user/linux.rb index a846d2657a..7d3a3c1163 100644 --- a/lib/chef/provider/user/linux.rb +++ b/lib/chef/provider/user/linux.rb @@ -24,23 +24,23 @@ class Chef provides :user, os: "linux" def create_user - shell_out_compact!("useradd", universal_options, useradd_options, new_resource.username) + shell_out!("useradd", universal_options, useradd_options, new_resource.username) end def manage_user - shell_out_compact!("usermod", universal_options, usermod_options, new_resource.username) + shell_out!("usermod", universal_options, usermod_options, new_resource.username) end def remove_user - shell_out_compact!("userdel", userdel_options, new_resource.username) + shell_out!("userdel", userdel_options, new_resource.username) end def lock_user - shell_out_compact!("usermod", "-L", new_resource.username) + shell_out!("usermod", "-L", new_resource.username) end def unlock_user - shell_out_compact!("usermod", "-U", new_resource.username) + shell_out!("usermod", "-U", new_resource.username) end # common to usermod and useradd @@ -88,7 +88,7 @@ class Chef def check_lock # there's an old bug in rhel (https://bugzilla.redhat.com/show_bug.cgi?id=578534) # which means that both 0 and 1 can be success. - passwd_s = shell_out_compact("passwd", "-S", new_resource.username, returns: [ 0, 1 ]) + passwd_s = shell_out("passwd", "-S", new_resource.username, returns: [ 0, 1 ]) # checking "does not exist" has to come before exit code handling since centos and ubuntu differ in exit codes if passwd_s.stderr =~ /does not exist/ diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb index 695dbfd539..42d44bab51 100644 --- a/lib/chef/provider/user/pw.rb +++ b/lib/chef/provider/user/pw.rb @@ -31,19 +31,19 @@ class Chef end def create_user - shell_out_compact!("pw", "useradd", set_options) + shell_out!("pw", "useradd", set_options) modify_password end def manage_user - shell_out_compact!("pw", "usermod", set_options) + shell_out!("pw", "usermod", set_options) modify_password end def remove_user command = [ "pw", "userdel", new_resource.username ] command << "-r" if new_resource.manage_home - shell_out_compact!(command) + shell_out!(command) end def check_lock @@ -57,11 +57,11 @@ class Chef end def lock_user - shell_out_compact!("pw", "lock", new_resource.username) + shell_out!("pw", "lock", new_resource.username) end def unlock_user - shell_out_compact!("pw", "unlock", new_resource.username) + shell_out!("pw", "unlock", new_resource.username) end def set_options diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb index 1abe660cfd..38e7f8cb31 100644 --- a/lib/chef/provider/user/solaris.rb +++ b/lib/chef/provider/user/solaris.rb @@ -30,18 +30,18 @@ class Chef PASSWORD_FILE = "/etc/shadow" def create_user - shell_out_compact!("useradd", universal_options, useradd_options, new_resource.username) + shell_out!("useradd", universal_options, useradd_options, new_resource.username) manage_password end def manage_user manage_password return if universal_options.empty? && usermod_options.empty? - shell_out_compact!("usermod", universal_options, usermod_options, new_resource.username) + shell_out!("usermod", universal_options, usermod_options, new_resource.username) end def remove_user - shell_out_compact!("userdel", userdel_options, new_resource.username) + shell_out!("userdel", userdel_options, new_resource.username) end def check_lock @@ -56,11 +56,11 @@ class Chef end def lock_user - shell_out_compact!("passwd", "-l", new_resource.username) + shell_out!("passwd", "-l", new_resource.username) end def unlock_user - shell_out_compact!("passwd", "-u", new_resource.username) + shell_out!("passwd", "-u", new_resource.username) end private diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb index c09cc0d3a5..855da325a0 100644 --- a/lib/chef/provider/user/useradd.rb +++ b/lib/chef/provider/user/useradd.rb @@ -36,7 +36,7 @@ class Chef useradd.concat(universal_options) useradd.concat(useradd_options) end - shell_out_compact!(command) + shell_out!(command) end def manage_user @@ -44,7 +44,7 @@ class Chef command = compile_command("usermod") do |u| u.concat(universal_options) end - shell_out_compact!(command) + shell_out!(command) end def remove_user @@ -52,13 +52,13 @@ class Chef command << "-r" if new_resource.manage_home command << "-f" if new_resource.force command << new_resource.username - shell_out_compact!(command) + shell_out!(command) end def check_lock # we can get an exit code of 1 even when it's successful on # rhel/centos (redhat bug 578534). See additional error checks below. - passwd_s = shell_out_compact!("passwd", "-S", new_resource.username, returns: [0, 1]) + passwd_s = shell_out!("passwd", "-S", new_resource.username, returns: [0, 1]) if whyrun_mode? && passwd_s.stdout.empty? && passwd_s.stderr.match(/does not exist/) # if we're in whyrun mode and the user is not yet created we assume it would be return false @@ -79,7 +79,7 @@ class Chef unless passwd_s.exitstatus == 0 raise_lock_error = false if %w{redhat centos}.include?(node[:platform]) - passwd_version_check = shell_out_compact!("rpm", "-q", "passwd") + passwd_version_check = shell_out!("rpm", "-q", "passwd") passwd_version = passwd_version_check.stdout.chomp unless passwd_version == "passwd-0.73-1" @@ -96,11 +96,11 @@ class Chef end def lock_user - shell_out_compact!("usermod", "-L", new_resource.username) + shell_out!("usermod", "-L", new_resource.username) end def unlock_user - shell_out_compact!("usermod", "-U", new_resource.username) + shell_out!("usermod", "-U", new_resource.username) end def compile_command(base_command) diff --git a/lib/chef/provider/windows_task.rb b/lib/chef/provider/windows_task.rb index 0bb28c66c6..1676ec3f6b 100644 --- a/lib/chef/provider/windows_task.rb +++ b/lib/chef/provider/windows_task.rb @@ -100,15 +100,13 @@ class Chef def load_current_resource @current_resource = Chef::Resource::WindowsTask.new(new_resource.name) - task = TaskScheduler.new - if task.exists?(new_resource.task_name) - @current_resource.exists = true + task = TaskScheduler.new(new_resource.task_name, nil, "\\", false) + @current_resource.exists = task.exists?(new_resource.task_name) + if @current_resource.exists task.get_task(new_resource.task_name) @current_resource.task = task pathed_task_name = new_resource.task_name.start_with?('\\') ? new_resource.task_name : "\\#{new_resource.task_name}" @current_resource.task_name(pathed_task_name) - else - @current_resource.exists = false end @current_resource end @@ -133,10 +131,10 @@ class Chef converge_by("#{new_resource} task created") do task = TaskScheduler.new if new_resource.frequency == :none - task.new_work_item(new_resource.task_name, {}) + task.new_work_item(new_resource.task_name, {}, { user: new_resource.user, password: new_resource.password }) task.activate(new_resource.task_name) else - task.new_work_item(new_resource.task_name, trigger) + task.new_work_item(new_resource.task_name, trigger, { user: new_resource.user, password: new_resource.password }) end task.application_name = new_resource.command task.parameters = new_resource.command_arguments if new_resource.command_arguments 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/chef_handler.rb b/lib/chef/resource/chef_handler.rb index ceed235840..6d55f882bd 100644 --- a/lib/chef/resource/chef_handler.rb +++ b/lib/chef/resource/chef_handler.rb @@ -15,6 +15,8 @@ # limitations under the License. # +require "chef/resource" + class Chef class Resource class ChefHandler < Chef::Resource diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb index d10113be56..f3fa5d0314 100644 --- a/lib/chef/resource/dsc_script.rb +++ b/lib/chef/resource/dsc_script.rb @@ -16,6 +16,7 @@ # limitations under the License. # +require "chef/resource" require "chef/exceptions" require "chef/dsl/powershell" diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb index d16355d027..e85a75e906 100644 --- a/lib/chef/resource/freebsd_package.rb +++ b/lib/chef/resource/freebsd_package.rb @@ -46,7 +46,7 @@ class Chef # # @return [Boolean] do we support pkgng def supports_pkgng? - ships_with_pkgng? || !!shell_out_compact!("make", "-V", "WITH_PKGNG", :env => nil).stdout.match(/yes/i) + ships_with_pkgng? || !!shell_out!("make", "-V", "WITH_PKGNG", :env => nil).stdout.match(/yes/i) end private @@ -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/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb index dee132a1b4..9d8c7b2596 100644 --- a/lib/chef/resource/homebrew_package.rb +++ b/lib/chef/resource/homebrew_package.rb @@ -30,7 +30,8 @@ class Chef description "Use the homebrew_package resource to manage packages for the macOS platform." introduced "12.0" - property :homebrew_user, [ String, Integer ] + property :homebrew_user, [ String, Integer ], + description: "The name of the Homebrew owner to be used by the chef-client when executing a command." end end diff --git a/lib/chef/resource/hostname.rb b/lib/chef/resource/hostname.rb index 878f502dae..02996f4464 100644 --- a/lib/chef/resource/hostname.rb +++ b/lib/chef/resource/hostname.rb @@ -1,3 +1,19 @@ +# +# 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 # Sets the hostname and updates /etc/hosts on *nix systems diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb index f209e419dd..3493cec9db 100644 --- a/lib/chef/resource/http_request.rb +++ b/lib/chef/resource/http_request.rb @@ -32,8 +32,11 @@ class Chef default_action :get allowed_actions :get, :patch, :put, :post, :delete, :head, :options - property :url, String, identity: true - property :headers, Hash, default: lazy { Hash.new } + property :url, String, identity: true, + description: "The URL to which an HTTP request is sent." + + property :headers, Hash, default: lazy { Hash.new }, + description: "A Hash of custom headers." def initialize(name, run_context = nil) super diff --git a/lib/chef/resource/ifconfig.rb b/lib/chef/resource/ifconfig.rb index 579a4eeedb..84ee249ec4 100644 --- a/lib/chef/resource/ifconfig.rb +++ b/lib/chef/resource/ifconfig.rb @@ -35,23 +35,63 @@ class Chef default_action :add allowed_actions :add, :delete, :enable, :disable - property :target, String, name_property: true - property :hwaddr, String - property :mask, String - property :family, String, default: "inet" - property :inet_addr, String - property :bcast, String - property :mtu, String - property :metric, String - property :device, String, identity: true - property :onboot, String - property :network, String - property :bootproto, String - property :onparent, String - property :ethtool_opts, String - property :bonding_opts, String - property :master, String - property :slave, String + property :target, String, + name_property: true, + description: "The IP address that is to be assigned to the network interface. If not specified we'll use the resource's name." + + property :hwaddr, String, + description: "The hardware address for the network interface." + + property :mask, String, + description: "The decimal representation of the network mask. For example: 255.255.255.0." + + property :family, String, + default: "inet", introduced: "14.0", + description: "Networking family option for Debian-based systems. For example: inet or inet6." + + property :inet_addr, String, + description: "The Internet host address for the network interface." + + property :bcast, String, + description: "The broadcast address for a network interface. On some platforms this property is not set using ifconfig, but instead is added to the startup configuration file for the network interface." + + property :mtu, String, + description: "The maximum transmission unit (MTU) for the network interface." + + property :metric, String, + description: "The routing metric for the interface." + + property :device, String, + identity: true, + description: "The network interface to be configured." + + property :onboot, String, + description: "Bring up the network interface on boot." + + property :network, String, + description: "The address for the network interface." + + property :bootproto, String, + description: "The boot protocol used by a network interface." + + property :onparent, String, + description: "Bring up the network interface when its parent interface is brought up." + + property :ethtool_opts, String, + introduced: "13.4", + description: "Options to be passed to ethtool(8). For example: -A eth0 autoneg off rx off tx off" + + property :bonding_opts, String, + introduced: "13.4", + description: "Bonding options to pass via BONDING_OPTS on RHEL and CentOS. For example: mode=active-backup miimon=100" + + property :master, String, + introduced: "13.4", + description: "Specifies the channel bonding interface to which the Ethernet interface is linked." + + property :slave, String, + introduced: "13.4", + description: "When set to yes, this device is controlled by the channel bonding interface that is specified via the master property." end end end diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb index 70e3bfee81..ff154e8bd8 100644 --- a/lib/chef/resource/ips_package.rb +++ b/lib/chef/resource/ips_package.rb @@ -30,7 +30,9 @@ class Chef allowed_actions :install, :remove, :upgrade - property :accept_license, [TrueClass, FalseClass], default: false, desired_state: false + property :accept_license, [TrueClass, FalseClass], + default: false, desired_state: false, + description: "Accept an end-user license agreement, automatically." end 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/launchd.rb b/lib/chef/resource/launchd.rb index 9161efa6ea..df01675de1 100644 --- a/lib/chef/resource/launchd.rb +++ b/lib/chef/resource/launchd.rb @@ -30,16 +30,39 @@ class Chef default_action :create allowed_actions :create, :create_if_missing, :delete, :enable, :disable, :restart - property :label, String, identity: true, name_property: true - property :backup, [Integer, FalseClass], desired_state: false - property :cookbook, String, desired_state: false - property :group, [String, Integer] - property :plist_hash, Hash - property :mode, [String, Integer] - property :owner, [String, Integer] - property :path, String - property :source, String - property :session_type, String + property :label, String, + identity: true, name_property: true, + description: "The unique identifier for the job." + + property :backup, [Integer, FalseClass], + desired_state: false, + description: "The number of backups to be kept in /var/chef/backup. Set to false to prevent backups from being kept." + + property :cookbook, String, + desired_state: false, + description: "The name of the cookbook in which the source files are located." + + property :group, [String, Integer], + description: "When launchd is run as the root user, the group to run the job as. If the username property is specified and this property is not, this value is set to the default group for the user." + + property :plist_hash, Hash, + introduced: "12.19", + description: "A Hash of key value pairs used to create the launchd property list." + + property :mode, [String, Integer], + description: "A quoted 3-5 character string that defines the octal mode. For example: '755', '0755', or 00755." + + property :owner, [String, Integer], + description: "A string or ID that identifies the group owner by user name, including fully qualified user names such as domain_user or user@domain. If this value is not specified, existing owners remain unchanged and new owner assignments use the current user (when necessary)." + + property :path, String, + description: "The path to the directory. Using a fully qualified path is recommended, but is not always required." + + property :source, String, + description: "The path to the launchd property list." + + property :session_type, String, + description: "The type of launchd plist to be created. Possible values: system (default) or user." # StartCalendarInterval has some gotchas so we coerce it to help sanity # check. According to `man 5 launchd.plist`: @@ -50,96 +73,180 @@ class Chef # this means that an entry like: # { "Hour"=>0, "Weekday"=>"6-7"} # will not just run on midnight of Sat and Sun, rather it will run _every_ midnight. - property :start_calendar_interval, [Hash, Array], coerce: proc { |type| - # Coerce into an array of hashes to make validation easier - array = if type.is_a?(Array) - type - else - [type] - end - - # Check to make sure that our array only has hashes - unless array.all? { |obj| obj.is_a?(Hash) } - error_msg = "start_calendar_interval must be a single hash or an array of hashes!" - raise Chef::Exceptions::ValidationFailed, error_msg - end - - # Make sure the hashes don't have any incorrect keys/values - array.each do |entry| - allowed_keys = %w{Minute Hour Day Weekday Month} - unless entry.keys.all? { |key| allowed_keys.include?(key) } - failed_keys = entry.keys.reject { |k| allowed_keys.include?(k) }.join(", ") - error_msg = "The following key(s): #{failed_keys} are invalid for start_calendar_interval, must be one of: #{allowed_keys.join(", ")}" - raise Chef::Exceptions::ValidationFailed, error_msg - end - - unless entry.values.all? { |val| val.is_a?(Integer) } - failed_values = entry.values.reject { |val| val.is_a?(Integer) }.join(", ") - error_msg = "Invalid value(s) (#{failed_values}) for start_calendar_interval item. Values must be integers!" - raise Chef::Exceptions::ValidationFailed, error_msg - end - end - - # Don't return array if we only have one entry - if array.size == 1 - array.first - else - array - end - } - - property :type, String, default: "daemon", coerce: proc { |type| - type = type ? type.downcase : "daemon" - types = %w{daemon agent} - - unless types.include?(type) - error_msg = "type must be daemon or agent" - raise Chef::Exceptions::ValidationFailed, error_msg - end - type - } + property :start_calendar_interval, [Hash, Array], + description: "A Hash (similar to crontab) that defines the calendar frequency at which a job is started or an Array.", + coerce: proc { |type| + # Coerce into an array of hashes to make validation easier + array = if type.is_a?(Array) + type + else + [type] + end + + # Check to make sure that our array only has hashes + unless array.all? { |obj| obj.is_a?(Hash) } + error_msg = "start_calendar_interval must be a single hash or an array of hashes!" + raise Chef::Exceptions::ValidationFailed, error_msg + end + + # Make sure the hashes don't have any incorrect keys/values + array.each do |entry| + allowed_keys = %w{Minute Hour Day Weekday Month} + unless entry.keys.all? { |key| allowed_keys.include?(key) } + failed_keys = entry.keys.reject { |k| allowed_keys.include?(k) }.join(", ") + error_msg = "The following key(s): #{failed_keys} are invalid for start_calendar_interval, must be one of: #{allowed_keys.join(", ")}" + raise Chef::Exceptions::ValidationFailed, error_msg + end + + unless entry.values.all? { |val| val.is_a?(Integer) } + failed_values = entry.values.reject { |val| val.is_a?(Integer) }.join(", ") + error_msg = "Invalid value(s) (#{failed_values}) for start_calendar_interval item. Values must be integers!" + raise Chef::Exceptions::ValidationFailed, error_msg + end + end + + # Don't return array if we only have one entry + if array.size == 1 + array.first + else + array + end + } + + property :type, String, + description: "The type of resource. Possible values: daemon (default), agent.", + default: "daemon", coerce: proc { |type| + type = type ? type.downcase : "daemon" + types = %w{daemon agent} + + unless types.include?(type) + error_msg = "type must be daemon or agent" + raise Chef::Exceptions::ValidationFailed, error_msg + end + type + } # Apple LaunchD Keys - property :abandon_process_group, [ TrueClass, FalseClass ] - property :debug, [ TrueClass, FalseClass ] - property :disabled, [ TrueClass, FalseClass ], default: false - property :enable_globbing, [ TrueClass, FalseClass ] - property :enable_transactions, [ TrueClass, FalseClass ] - property :environment_variables, Hash - property :exit_timeout, Integer - property :hard_resource_limits, Hash - property :inetd_compatibility, Hash - property :init_groups, [ TrueClass, FalseClass ] - property :keep_alive, [ TrueClass, FalseClass, Hash ] - property :launch_only_once, [ TrueClass, FalseClass ] - property :ld_group, String - property :limit_load_from_hosts, Array - property :limit_load_to_hosts, Array - property :limit_load_to_session_type, [ Array, String ] - property :low_priority_io, [ TrueClass, FalseClass ] - property :mach_services, Hash - property :nice, Integer - property :on_demand, [ TrueClass, FalseClass ] - property :process_type, String - property :program, String - property :program_arguments, Array - property :queue_directories, Array - property :root_directory, String - property :run_at_load, [ TrueClass, FalseClass ] - property :sockets, Hash - property :soft_resource_limits, Array - property :standard_error_path, String - property :standard_in_path, String - property :standard_out_path, String - property :start_interval, Integer - property :start_on_mount, [ TrueClass, FalseClass ] - property :throttle_interval, Integer - property :time_out, Integer - property :umask, Integer - property :username, String - property :wait_for_debugger, [ TrueClass, FalseClass ] - property :watch_paths, Array - property :working_directory, String + property :abandon_process_group, [ TrueClass, FalseClass ], + description: "If a job dies, all remaining processes with the same process ID may be kept running. Set to true to kill all remaining processes." + + property :debug, [ TrueClass, FalseClass ], + description: "Sets the log mask to LOG_DEBUG for this job." + + property :disabled, [ TrueClass, FalseClass ], default: false, + description: "Hints to launchctl to not submit this job to launchd." + + property :enable_globbing, [ TrueClass, FalseClass ], + description: "Update program arguments before invocation." + + property :enable_transactions, [ TrueClass, FalseClass ], + description: "Track in-progress transactions; if none, then send the SIGKILL signal." + + property :environment_variables, Hash, + description: "Additional environment variables to set before running a job." + + property :exit_timeout, Integer, + description: "The amount of time (in seconds) launchd waits before sending a SIGKILL signal." + + property :hard_resource_limits, Hash, + description: "A Hash of resource limits to be imposed on a job." + + property :inetd_compatibility, Hash, + description: "Specifies if a daemon expects to be run as if it were launched from inetd. Set to wait => true to pass standard input, output, and error file descriptors. Set to wait => false to call the accept system call on behalf of the job, and then pass standard input, output, and error file descriptors." + + property :init_groups, [ TrueClass, FalseClass ], + description: "Specify if initgroups is called before running a job." + + property :keep_alive, [ TrueClass, FalseClass, Hash ], + introduced: "12.14", + description: "Keep a job running continuously (true) or allow demand and conditions on the node to determine if the job keeps running (false)." + + property :launch_only_once, [ TrueClass, FalseClass ], + description: "Specify if a job can be run only one time. Set this value to true if a job cannot be restarted without a full machine reboot." + + property :ld_group, String, + description: "The group name." + + property :limit_load_from_hosts, Array, + description: "An array of hosts to which this configuration file does not apply, i.e. 'apply this configuration file to all hosts not specified in this array'." + + property :limit_load_to_hosts, Array, + description: "An array of hosts to which this configuration file applies." + + property :limit_load_to_session_type, [ Array, String ], + description: "The session type(s) to which this configuration file applies." + + property :low_priority_io, [ TrueClass, FalseClass ], + description: "Specify if the kernel on the node should consider this daemon to be low priority during file system I/O." + + property :mach_services, Hash, + description: "Specify services to be registered with the bootstrap subsystem." + + property :nice, Integer, + description: "The program scheduling priority value in the range -20 to 20." + + property :on_demand, [ TrueClass, FalseClass ], + description: "Keep a job alive. Only applies to macOS version 10.4 (and earlier); use keep_alive instead for newer versions." + + property :process_type, String, + description: "The intended purpose of the job: Adaptive, Background, Interactive, or Standard." + + property :program, String, + 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." + + property :program_arguments, Array, + 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." + + property :queue_directories, Array, + description: "An array of non-empty directories which, if any are modified, will cause a job to be started." + + property :root_directory, String, + description: "chroot to this directory, and then run the job." + + property :run_at_load, [ TrueClass, FalseClass ], + description: "Launch a job once (at the time it is loaded)." + + property :sockets, Hash, + description: "A Hash of on-demand sockets that notify launchd when a job should be run." + + property :soft_resource_limits, Array, + description: "A Hash of resource limits to be imposed on a job." + + property :standard_error_path, String, + description: "The file to which standard error (stderr) is sent." + + property :standard_in_path, String, + description: "The file to which standard input (stdin) is sent." + + property :standard_out_path, String, + description: "The file to which standard output (stdout) is sent." + + property :start_interval, Integer, + description: "The frequency (in seconds) at which a job is started." + + property :start_on_mount, [ TrueClass, FalseClass ], + description: "Start a job every time a file system is mounted." + + property :throttle_interval, Integer, + description: "The frequency (in seconds) at which jobs are allowed to spawn." + + property :time_out, Integer, + description: "The amount of time (in seconds) a job may be idle before it times out. If no value is specified, the default timeout value for launchd will be used." + + property :umask, Integer, + description: "A decimal value to pass to umask before running a job." + + property :username, String, + description: "When launchd is run as the root user, the user to run the job as." + + property :wait_for_debugger, [ TrueClass, FalseClass ], + description: "Specify if launchd has a job wait for a debugger to attach before executing code." + + property :watch_paths, Array, + description: "An array of paths which, if any are modified, will cause a job to be started." + + property :working_directory, String, + description: "Chdir to this directory, and then run the job." end end end diff --git a/lib/chef/resource/log.rb b/lib/chef/resource/log.rb index a9dea6b104..b97b5c9e66 100644 --- a/lib/chef/resource/log.rb +++ b/lib/chef/resource/log.rb @@ -37,8 +37,13 @@ class Chef " entry that is not built into the resource collection, use Chef::Log instead"\ " of the log resource.)" - property :message, String, name_property: true, identity: true - property :level, Symbol, equal_to: [ :debug, :info, :warn, :error, :fatal ], default: :info + property :message, String, + name_property: true, identity: true, + description: "The message to be added to a log file. If not specified we'll use the resource's name instead." + + property :level, Symbol, + equal_to: [ :debug, :info, :warn, :error, :fatal ], default: :info, + description: "The logging level to display this message at." allowed_actions :write default_action :write diff --git a/lib/chef/resource/mdadm.rb b/lib/chef/resource/mdadm.rb index 3b54a53e98..3fc5b7c338 100644 --- a/lib/chef/resource/mdadm.rb +++ b/lib/chef/resource/mdadm.rb @@ -32,14 +32,35 @@ class Chef default_action :create allowed_actions :create, :assemble, :stop - property :chunk, Integer, default: 16 - property :devices, Array, default: lazy { [] } - property :exists, [ TrueClass, FalseClass ], default: false - property :level, Integer, default: 1 - property :metadata, String, default: "0.90" - property :bitmap, String - property :raid_device, String, identity: true, name_property: true - property :layout, String + property :chunk, Integer, + default: 16, + description: "The chunk size. This property should not be used for a RAID 1 mirrored pair (i.e. when the level property is set to 1)." + + property :devices, Array, + default: lazy { [] }, + description: "The devices to be part of a RAID array." + + property :exists, [ TrueClass, FalseClass ], + default: false, + description: "Indicates whether the RAID array exists." + + property :level, Integer, + default: 1, + description: "The RAID level." + + property :metadata, String, + default: "0.90", + description: "The superblock type for RAID metadata." + + property :bitmap, String, + description: "The path to a file in which a write-intent bitmap is stored." + + property :raid_device, String, + identity: true, name_property: true, + description: "The name of the RAID device. We'll use the resource's name if this isn't specified." + + property :layout, String, + description: "The RAID5 parity algorithm. Possible values: left-asymmetric (or la), left-symmetric (or ls), right-asymmetric (or ra), or right-symmetric (or rs)." end end end diff --git a/lib/chef/resource/ohai.rb b/lib/chef/resource/ohai.rb index a84d521333..b286412434 100644 --- a/lib/chef/resource/ohai.rb +++ b/lib/chef/resource/ohai.rb @@ -17,6 +17,8 @@ # limitations under the License. # +require "chef/resource" + class Chef class Resource class Ohai < Chef::Resource diff --git a/lib/chef/resource/ohai_hint.rb b/lib/chef/resource/ohai_hint.rb index 6eb36aea13..f485222ec6 100644 --- a/lib/chef/resource/ohai_hint.rb +++ b/lib/chef/resource/ohai_hint.rb @@ -15,6 +15,8 @@ # limitations under the License. # +require "chef/resource" + class Chef class Resource class OhaiHint < Chef::Resource 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..fd076ffad3 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 @@ -116,7 +117,7 @@ class Chef def features_to_install @install ||= begin # disabled features are always available to install - available_for_install = node["dism_features_cache"]["disabled"] + available_for_install = node["dism_features_cache"]["disabled"].dup # if the user passes a source then removed features are also available for installation available_for_install.concat(node["dism_features_cache"]["removed"]) if new_resource.source @@ -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 cc1af2a5df..b21f2fe6f7 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" @@ -93,6 +94,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/util/selinux.rb b/lib/chef/util/selinux.rb index 0d973b0376..fb0c98cff5 100644 --- a/lib/chef/util/selinux.rb +++ b/lib/chef/util/selinux.rb @@ -52,7 +52,7 @@ class Chef restorecon_flags << "-r" if recursive restorecon_flags << file_path Chef::Log.trace("Restoring selinux security content with #{restorecon_path}") - shell_out_compact!(restorecon_path, restorecon_flags) + shell_out!(restorecon_path, restorecon_flags) else Chef::Log.warn "Can not find 'restorecon' on the system. Skipping selinux security context restore." end diff --git a/lib/chef/version.rb b/lib/chef/version.rb index 6b7512dda9..4348c4d952 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.18") end # |