Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

can not believe this: chef lazy block get executed 3 times

I can not believe this! I ran into a chef issue: file content lazy ruby block gets executed 3 times, but it is supposed to be only run once.

$ sudo cat /var/chef/cache/cookbooks/infra-tmp/recipes/default.rb
aaa = 'aaaaaa'
puts "=========before"
file '/tmp/a.pem' do
  puts "==== inner begin"
  content lazy { xxx(aaa) }
end
puts "=========end"

the xxx is a common function defined in infra-common libraries,

def xxx(aaa=nil)
        puts "========xxx: #{aaa}"
        puts caller
        aaa
end

guess how many times the xxx get executed? 3!

$ sudo chef-client -o infra-tmp --skip-cookbook-sync
Starting Chef Client, version 13.12.3
...
Compiling Cookbooks...
=========before
==== inner begin
=========end
Converging 1 resources
Recipe: infra-tmp::default
  * file[/tmp/a.pem] action create========xxx: aaaaaa
/var/chef/cache/cookbooks/infra-tmp/recipes/default.rb:9:in `block (2 levels) in from_file'
...
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:191:in `managing_content?'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:94:in `load_current_resource'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider.rb:154:in `run_action'
...
========xxx: aaaaaa
/var/chef/cache/cookbooks/infra-tmp/recipes/default.rb:9:in `block (2 levels) in from_file'
...
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file/content.rb:27:in `file_for_provider'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/file_content_management/content_base.rb:40:in `tempfile'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:450:in `tempfile'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:327:in `do_generate_content'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:140:in `action_create'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider.rb:171:in `run_action'
...
========xxx: aaaaaa
/var/chef/cache/cookbooks/infra-tmp/recipes/default.rb:9:in `block (2 levels) in from_file'
...
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file/content.rb:29:in `file_for_provider'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/file_content_management/content_base.rb:40:in `tempfile'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:450:in `tempfile'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:327:in `do_generate_content'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file.rb:140:in `action_create'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider.rb:171:in `run_action'
...

I've checked the chef source code,

$ cat -n /opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.12.3/lib/chef/provider/file/content.rb | grep -vE '^s*(#|$)'
    18
    19  require "chef/file_content_management/content_base"
    20  require "chef/file_content_management/tempfile"
    21
    22  class Chef
    23    class Provider
    24      class File
    25        class Content < Chef::FileContentManagement::ContentBase
    26          def file_for_provider
    27            if @new_resource.content
    28              tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile
    29              tempfile.write(@new_resource.content)
    30              tempfile.close
    31              tempfile
    32            else
    33              nil
    34            end
    35          end
    36        end
    37      end
    38    end
    39  end

Turns out it is because @new_resource.content being referenced 3 times, without using a local var to cache it.

Is this a bug of Chef? Not sure whether other chef resource has same bug.

EDIT: I ended up with @var instance var to cache, instead of node.run_state which cause multi custom resources only use first cached value.

file ... do
  ...
  content lazy {
          @any_name || (@any_name  = some_function(some_param))
  }
  ...
end
question from:https://stackoverflow.com/questions/65879139/can-not-believe-this-chef-lazy-block-get-executed-3-times

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...