kemra102
kemra102

Reputation: 531

Chef: no implicit conversion of String into Integer TypeError

I wrote a small Chef library that looks like this:

module Test
  module Search
    extend self

    def single_node(type, value)
      result = Chef::Search::Query.new.search(:node, "#{type}:#{value}",
                                              filter_result: {
                                                'name' => ['name']
                                              }).map { |n| n['name'] }.first
      return result
    end

  end
end

When running test code against it I get the following error:

TypeError
---------
no implicit conversion of String into Integer

         1:  module Test
         2:    module Search
         3:      extend self
         4:      def single_node(type, value)
         5:        result = Chef::Search::Query.new.search(:node, "#{type}:#{value}",
         6:                                                filter_result: {
         7:                                                  'name' => ['name']
         8>>                                               }).map { |n| n['name'] }.first
         9:        return result
        10:      end


        13:  end
        14:

After some playing around I found that the search contained this information:

[[{"name"=>"influxdb.example.org"}], 0, 1].

This seems odd as the search options used return something different when searching from within the Chef DSL.

Upvotes: 2

Views: 1785

Answers (2)

Tensibai
Tensibai

Reputation: 15784

When executing the search in a recipe you're calling the search method in recipe DSL, which already iterate over the results before sending them back.

When you call Chef::Sarch::Query.new.searchyou're calling the underlying method out of the dsl helper and have to iterate over the results yourself if you don't pass a block to the method to work on the results.

You end up here which returns an array containing the query result array, along with the start and size of results (for pagination on UI).

So the final answer as already been given by @Oleander, call first before map, to call map in the result part of the return (first array entry) ignoring the pagination variables.

Or to get the same behavior as in the recipe DSL use Chef::DSL::DataQuery like this:

require 'chef/dsl/data_query'

module Test
  module Search
    extend self
    include Chef::DSL::DataQuery

    def single_node(type, value)
      result = search(:node, "#{type}:#{value}",
                             filter_result: {
                               'name' => ['name']
                             }).map { |n| n['name'] }.first
      return result
    end
  end
end

On the same idea to shorten your code:

require 'chef/dsl/data_query'

module Test
  module Search
    extend self
    include Chef::DSL::DataQuery

    def single_node(type, value)
      return search(:node, "#{type}:#{value}",
                             filter_result: {
                               'name' => ['name']
                             }).first['name']
    end
  end
end

Which return the first result too and get it's name, should be a little quicker as it does not have to 'subset' all entries but only the first one.

Upvotes: 4

Linus Oleander
Linus Oleander

Reputation: 18157

If what you posted is your return value, then just run first on it and you're done.

result = Chef::Search::Query.new.search(:node, "#{type}:#{value}", filter_result: {
  'name' => ['name']
}).first.map { |n| n['name'] }.first

Upvotes: 2

Related Questions