diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 7b1e3193..9bf249e1 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,11 +1,54 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2025-03-10 20:03:26 UTC using RuboCop version 1.70.0. +# on 2025-06-05 11:36:25 UTC using RuboCop version 1.70.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +Layout/EmptyLineAfterGuardClause: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +Layout/HeredocIndentation: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowDoxygenCommentStyle, AllowGemfileRubyComment, AllowRBSInlineAnnotation, AllowSteepAnnotation. +Layout/LeadingCommentSpace: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: leading, trailing +Layout/LineContinuationLeadingSpace: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: space, no_space +Layout/LineContinuationSpacing: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: aligned, indented +Layout/LineEndStringConcatenationIndentation: + Exclude: + - 'lib/puppet/resource_api.rb' + # Offense count: 19 # Configuration parameters: AllowComments, AllowEmptyLambdas. Lint/EmptyBlock: @@ -24,6 +67,12 @@ Lint/EmptyClass: - 'spec/puppet/resource_api/transport_spec.rb' - 'spec/puppet/resource_api_spec.rb' +# Offense count: 5 +# This cop supports safe autocorrection (--autocorrect). +Lint/RedundantCopDisableDirective: + Exclude: + - 'lib/puppet/resource_api.rb' + # Offense count: 25 # Configuration parameters: IgnoredMetadata. RSpec/DescribeClass: @@ -89,7 +138,7 @@ Style/CollectionCompact: Exclude: - 'lib/puppet/resource_api.rb' -# Offense count: 3 +# Offense count: 4 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowSplatArgument. Style/HashConversion: @@ -106,8 +155,86 @@ Style/HashEachMethods: Exclude: - 'lib/puppet/resource_api/type_definition.rb' +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/HashTransformValues: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 6 +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantAssignment: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, AllowInnerSlashes. +# SupportedStyles: slashes, percent_r, mixed +Style/RegexpLiteral: + Exclude: + - 'lib/puppet/resource_api.rb' + # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). Style/SlicingWithRange: Exclude: - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowModifier. +Style/SoleNestedConditional: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: Mode. +Style/StringConcatenation: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Style/SuperArguments: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: . +# SupportedStyles: percent, brackets +Style/SymbolArray: + EnforcedStyle: percent + MinSize: 5 + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments. +# AllowedMethods: define_method +Style/SymbolProc: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyleForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma +Style/TrailingCommaInArguments: + Exclude: + - 'lib/puppet/resource_api.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyleForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma +Style/TrailingCommaInHashLiteral: + Exclude: + - 'lib/puppet/resource_api.rb' diff --git a/lib/puppet/resource_api.rb b/lib/puppet/resource_api.rb index 9f790d34..ed2504c7 100644 --- a/lib/puppet/resource_api.rb +++ b/lib/puppet/resource_api.rb @@ -33,7 +33,9 @@ def register_type(definition) # this has to happen before Puppet::Type.newtype starts autoloading providers # it also needs to be guarded against the namespace already being defined by something # else to avoid ruby warnings - Puppet::Provider.const_set(class_name_from_type_name(definition[:name]), Module.new) unless Puppet::Provider.const_defined?(class_name_from_type_name(definition[:name]), false) + unless Puppet::Provider.const_defined?(class_name_from_type_name(definition[:name]), false) + Puppet::Provider.const_set(class_name_from_type_name(definition[:name]), Module.new) + end Puppet::Type.newtype(definition[:name].to_sym) do # The :desc value is already cleaned up by the TypeDefinition validation @@ -64,7 +66,9 @@ def type_definition self.class.type_definition end - apply_to_device if type_definition.feature?('remote_resource') + if type_definition.feature?('remote_resource') + apply_to_device + end define_singleton_method(:rsapi_provider_get_cache) do # This gives a new cache per resource provider on each Puppet run: @@ -90,21 +94,27 @@ def initialize(attributes) # undo puppet's unwrapping of Sensitive values to provide a uniform experience for providers # See https://tickets.puppetlabs.com/browse/PDK-1091 for investigation and background sensitives.each do |name| - attributes[name] = Puppet::Pops::Types::PSensitiveType::Sensitive.new(attributes[name]) if attributes.key?(name) && !attributes[name].is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive) + if attributes.key?(name) && !attributes[name].is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive) + attributes[name] = Puppet::Pops::Types::PSensitiveType::Sensitive.new(attributes[name]) + end end # $stderr.puts "B: #{attributes.inspect}" - attributes = my_provider.canonicalize(context, [attributes])[0] if type_definition.feature?('canonicalize') + if type_definition.feature?('canonicalize') + attributes = my_provider.canonicalize(context, [attributes])[0] + end # the `Puppet::Resource::Ral.find` method, when `instances` does not return a match, uses a Hash with a `:name` key to create # an "absent" resource. This is often hit by `puppet resource`. This needs to work, even if the namevar is not called `name`. # This bit here relies on the default `title_patterns` (see below) to match the title back to the first (and often only) namevar if type_definition.attributes[:name].nil? && attributes[:title].nil? attributes[:title] = attributes.delete(:name) - attributes[:title] = @title if attributes[:title].nil? && !type_definition.namevars.empty? + if attributes[:title].nil? && !type_definition.namevars.empty? + attributes[:title] = @title + end end - super + super(attributes) end def name @@ -129,7 +139,7 @@ def rsapi_canonicalized_target_state @rsapi_canonicalized_target_state ||= begin # skip puppet's injected metaparams actual_params = @parameters.select { |k, _v| type_definition.attributes.key? k } - target_state = actual_params.transform_values(&:rs_value) + target_state = Hash[actual_params.map { |k, v| [k, v.rs_value] }] target_state = my_provider.canonicalize(context, [target_state]).first if type_definition.feature?('canonicalize') target_state end @@ -140,18 +150,17 @@ def rsapi_canonicalized_target_state def generate # If feature `custom_generate` has been set then call the generate function within the provider and return the given results return unless type_definition&.feature?('custom_generate') - should_hash = rsapi_canonicalized_target_state is_hash = rsapi_current_state title = rsapi_title # Ensure that a custom `generate` method has been created within the provider raise(Puppet::DevError, 'No generate method found within the types provider') unless my_provider.respond_to?(:generate) - # Call the providers custom `generate` method - my_provider.generate(context, title, is_hash, should_hash) + rules_resources = my_provider.generate(context, title, is_hash, should_hash) # Return array of resources + rules_resources end def rsapi_current_state @@ -163,7 +172,7 @@ def rsapi_current_state strict_check(cached_value) if cached_value @rsapi_current_state = cached_value end - + def rsapi_current_state=(value) rsapi_provider_get_cache.add(rsapi_title, value) @rsapi_current_state = value @@ -190,11 +199,11 @@ def to_resource_shim(resource) definition[:attributes].each do |name, options| type = Puppet::ResourceApi::DataTypeHandling.parse_puppet_type( :name, - options[:type] + options[:type], ) # skip read only vars and the namevar - next if %i[read_only namevar].include? options[:behaviour] + next if [:read_only, :namevar].include? options[:behaviour] # skip properties if the resource is being deleted next if definition[:attributes][:ensure] && @@ -221,7 +230,7 @@ def to_resource_shim(resource) custom_insync_trigger_options = { type: 'Enum[do_not_specify_in_manifest]', desc: 'A hidden property which enables a type with custom insync to perform an insync check without specifying any insyncable properties', - default: 'do_not_specify_in_manifest' + default: 'do_not_specify_in_manifest', } type_definition.create_attribute_in(self, :rsapi_custom_insync_trigger, :newproperty, Puppet::ResourceApi::Property, custom_insync_trigger_options) @@ -230,12 +239,16 @@ def to_resource_shim(resource) definition[:attributes].each do |name, options| # puts "#{name}: #{options.inspect}" - raise Puppet::ResourceError, "`#{options[:behaviour]}` is not a valid behaviour value" if options[:behaviour] && !(%i[read_only namevar parameter init_only].include? options[:behaviour]) + if options[:behaviour] + unless [:read_only, :namevar, :parameter, :init_only].include? options[:behaviour] + raise Puppet::ResourceError, "`#{options[:behaviour]}` is not a valid behaviour value" + end + end # TODO: using newparam everywhere would suppress change reporting # that would allow more fine-grained reporting through context, # but require more invest in hooking up the infrastructure to emulate existing data - if %i[parameter namevar].include? options[:behaviour] + if [:parameter, :namevar].include? options[:behaviour] param_or_property = :newparam parent = Puppet::ResourceApi::Parameter elsif options[:behaviour] == :read_only @@ -251,8 +264,20 @@ def to_resource_shim(resource) def self.rsapi_provider_get(names = nil) # If the cache has been marked as having all instances, then just return the - # full contents: - return rsapi_provider_get_cache.all if rsapi_provider_get_cache.cached_all? && names.nil? + # full contents or the filtered contents based on names: + if rsapi_provider_get_cache.cached_all? + return rsapi_provider_get_cache.all if names.nil? + + # If we have all instances cached but need specific ones, filter from cache + cached_resources = names.map { |name| rsapi_provider_get_cache.get(name) }.compact + return cached_resources unless cached_resources.empty? + end + + # For simple_get_filter, if we're asking for specific resources and they're cached, return those + if type_definition.feature?('simple_get_filter') && !names.nil? + cached_resources = names.map { |name| rsapi_provider_get_cache.get(name) }.compact + return cached_resources if names.length == cached_resources.length + end fetched = if type_definition.feature?('simple_get_filter') my_provider.get(context, names) @@ -343,18 +368,17 @@ def flush # puts 'flush' target_state = rsapi_canonicalized_target_state - retrieve unless rsapi_current_state + retrieve unless @rsapi_current_state - return if rsapi_current_state == target_state + return if @rsapi_current_state == target_state Puppet.debug("Target State: #{target_state.inspect}") # enforce init_only attributes - if Puppet.settings[:strict] != :off && rsapi_current_state && (rsapi_current_state[:ensure] == 'present' && target_state[:ensure] == 'present') + if Puppet.settings[:strict] != :off && @rsapi_current_state && (@rsapi_current_state[:ensure] == 'present' && target_state[:ensure] == 'present') target_state.each do |name, value| - next unless type_definition.attributes[name][:behaviour] == :init_only && value != rsapi_current_state[name] - - message = "Attempting to change `#{name}` init_only attribute value from `#{rsapi_current_state[name]}` to `#{value}`" + next unless type_definition.attributes[name][:behaviour] == :init_only && value != @rsapi_current_state[name] + message = "Attempting to change `#{name}` init_only attribute value from `#{@rsapi_current_state[name]}` to `#{value}`" case Puppet.settings[:strict] when :warning Puppet.warning(message) @@ -365,9 +389,9 @@ def flush end if type_definition.feature?('supports_noop') - my_provider.set(context, { rsapi_title => { is: rsapi_current_state, should: target_state } }, noop: noop?) + my_provider.set(context, { rsapi_title => { is: @rsapi_current_state, should: target_state } }, noop: noop?) else - my_provider.set(context, rsapi_title => { is: rsapi_current_state, should: target_state }) unless noop? + my_provider.set(context, rsapi_title => { is: @rsapi_current_state, should: target_state }) unless noop? end if context.failed? context.reset_failed @@ -375,16 +399,16 @@ def flush end # remember that we have successfully reached our desired state - self.rsapi_current_state = target_state + @rsapi_current_state = target_state end def raise_missing_attrs - error_msg = "The following mandatory attributes were not provided:\n * #{@missing_attrs.join(", \n * ")}" + error_msg = "The following mandatory attributes were not provided:\n * " + @missing_attrs.join(", \n * ") raise Puppet::ResourceError, error_msg if @missing_attrs.any? && (value(:ensure) != :absent && !value(:ensure).nil?) end def raise_missing_params - error_msg = "The following mandatory parameters were not provided:\n * #{@missing_params.join(", \n * ")}" + error_msg = "The following mandatory parameters were not provided:\n * " + @missing_params.join(", \n * ") raise Puppet::ResourceError, error_msg end @@ -415,14 +439,14 @@ def strict_check_canonicalize(current_state) # compare the clone against the current state to see if changes have been made by canonicalize return unless state_clone && (current_state != state_clone) - # :nocov: + #:nocov: # codecov fails to register this multiline as covered, even though simplecov does. - message = <<~MESSAGE.strip - #{type_definition.name}[#{@title}]#get has not provided canonicalized values. - Returned values: #{current_state.inspect} - Canonicalized values: #{state_clone.inspect} - MESSAGE - # :nocov: + message = <