lib/puppet/resource_api.rb in puppet-resource_api-1.4.2 vs lib/puppet/resource_api.rb in puppet-resource_api-1.5.0

- old
+ new

@@ -77,14 +77,25 @@ define_method(:initialize) do |attributes| # $stderr.puts "A: #{attributes.inspect}" if attributes.is_a? Puppet::Resource @title = attributes.title @catalog = attributes.catalog + sensitives = attributes.sensitive_parameters attributes = attributes.to_hash else @ral_find_absent = true + sensitives = [] end + + # 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| + 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}" if type_definition.feature?('canonicalize') attributes = my_provider.canonicalize(context, [attributes])[0] end @@ -186,13 +197,17 @@ defaultto :false # rubocop:disable Lint/BooleanSymbol elsif options[:default] == true # work around https://tickets.puppetlabs.com/browse/PUP-2368 defaultto :true # rubocop:disable Lint/BooleanSymbol else - defaultto options[:default] + # marshal the default option to decouple that from the actual value. + # we cache the dumped value in `marshalled`, but use a block to unmarshal + # everytime the value is requested. Objects that can't be marshalled + # See https://stackoverflow.com/a/8206537/4918 + marshalled = Marshal.dump(options[:default]) + defaultto { Marshal.load(marshalled) } # rubocop:disable Security/MarshalLoad end - # defaultto options[:default] end end if name == :ensure def insync?(is) @@ -299,46 +314,57 @@ define_singleton_method(:instances) do # puts 'instances' # force autoloading of the provider provider(type_definition.name) - my_provider.get(context).map do |resource_hash| + initial_fetch = if type_definition.feature?('simple_get_filter') + my_provider.get(context, []) + else + my_provider.get(context) + end + + initial_fetch.map do |resource_hash| type_definition.check_schema(resource_hash) - result = new(title: resource_hash[type_definition.namevars.first]) + # allow a :title from the provider to override the default + result = if resource_hash.key? :title + new(title: resource_hash[:title]) + else + new(title: resource_hash[type_definition.namevars.first]) + end result.cache_current_state(resource_hash) result end end define_method(:refresh_current_state) do - @rapi_current_state = if type_definition.feature?('simple_get_filter') - my_provider.get(context, [title]).first - else - my_provider.get(context).find { |h| namevar_match?(h) } - end + @rsapi_current_state = if type_definition.feature?('simple_get_filter') + my_provider.get(context, [title]).find { |h| namevar_match?(h) } + else + my_provider.get(context).find { |h| namevar_match?(h) } + end - if @rapi_current_state - type_definition.check_schema(@rapi_current_state) - strict_check(@rapi_current_state) if type_definition.feature?('canonicalize') + if @rsapi_current_state + type_definition.check_schema(@rsapi_current_state) + strict_check(@rsapi_current_state) if type_definition.feature?('canonicalize') else - @rapi_current_state = { title: title } - @rapi_current_state[:ensure] = :absent if type_definition.ensurable? + @rsapi_current_state = { title: title } + @rsapi_current_state[:ensure] = :absent if type_definition.ensurable? end end # Use this to set the current state from the `instances` method def cache_current_state(resource_hash) - @rapi_current_state = resource_hash - strict_check(@rapi_current_state) if type_definition.feature?('canonicalize') + @rsapi_current_state = resource_hash + strict_check(@rsapi_current_state) if type_definition.feature?('canonicalize') end define_method(:retrieve) do - refresh_current_state unless @rapi_current_state + refresh_current_state unless @rsapi_current_state - Puppet.debug("Current State: #{@rapi_current_state.inspect}") + Puppet.debug("Current State: #{@rsapi_current_state.inspect}") - result = Puppet::Resource.new(self.class, title, parameters: @rapi_current_state) + result = Puppet::Resource.new(self.class, title, parameters: @rsapi_current_state) # puppet needs ensure to be a symbol result[:ensure] = result[:ensure].to_sym if type_definition.ensurable? && result[:ensure].is_a?(String) raise_missing_attrs @@ -358,38 +384,38 @@ # skip puppet's injected metaparams actual_params = @parameters.select { |k, _v| type_definition.attributes.key? k } 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') - retrieve unless @rapi_current_state + retrieve unless @rsapi_current_state - return if @rapi_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 && @rapi_current_state && (@rapi_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 definition[:attributes][name][:behaviour] == :init_only && value != @rapi_current_state[name] - message = "Attempting to change `#{name}` init_only attribute value from `#{@rapi_current_state[name]}` to `#{value}`" + next unless 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) when :error raise Puppet::ResourceError, message end end end if type_definition.feature?('supports_noop') - my_provider.set(context, { title => { is: @rapi_current_state, should: target_state } }, noop: noop?) + my_provider.set(context, { title => { is: @rsapi_current_state, should: target_state } }, noop: noop?) else - my_provider.set(context, title => { is: @rapi_current_state, should: target_state }) unless noop? + my_provider.set(context, title => { is: @rsapi_current_state, should: target_state }) unless noop? end raise 'Execution encountered an error' if context.failed? # remember that we have successfully reached our desired state - @rapi_current_state = target_state + @rsapi_current_state = target_state end define_method(:raise_missing_attrs) do 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?)