Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define before_symlink callback using application cookbook?

Tags:

chef-infra

I am developing a cookbook to deploy a simple jekyll based blog. I use 'application' cookbook as a base. Everything works smoothly except chef simply ignores my defined callbacks.

Chef log contains entries about my callback, but I see no errors or outcomes of the callback execution.

Here is recipes/default.rb file:

include_recipe "git"

application "example_com" do
  path "/var/www/example.com"
  repository "[email protected]:xxx/xxx.git"
  revision "master"

  deploy_key <<EOF
-----BEGIN RSA PRIVATE KEY-----
..skip...
-----END RSA PRIVATE KEY-----
EOF

  # before_symlink "script/bootstrap"

  before_deploy do
    # raise
    # Chef::Log.info("INSANE!")
    execute "bundle exec rake generate" do
      cwd release_path
    end
  end
end

Here is the log where chef-client says it executes before_deploy callback:

[2012-10-06T10:06:20-04:00] INFO: Processing ruby_block[example_com before_deploy] action create (/var/cache/chef/cookbooks/application/providers/default.rb line 107)
[2012-10-06T10:06:20-04:00] DEBUG: Got callback before_deploy: #<Proc:0x00007f0509788088@/var/cache/chef/cookbooks/example_com/recipes/default.rb:24>
[2012-10-06T10:06:20-04:00] INFO: application[example_com] running callback before_deploy
[2012-10-06T10:06:20-04:00] INFO: ruby_block[example_com before_deploy] called
[2012-10-06T10:06:20-04:00] INFO: Processing deploy_revision[example_com] action deploy (/var/cache/chef/cookbooks/application/providers/default.rb line 122)

I also tried to define callback using string, but the result is the same. Chef shows error when there is no file with callback definition and simply ignores the file if it is in the right place.

Update 1

After digging deeper inside Chef sources I realized that callbacks are executed in separate chef runner and this happens not instantly. When code in application cookbook calls _recipe_eval_ to evaluate callback body Chef creates separate runner and the code does not executed until something call converge method.

So, I modified application cookbook a bit. I added call converge just after _recipe_eval_ and everything started to work.

I think this is a bug and I am going to create an issue in official Opscode tracker. However, any comments are very welcome!

Here is modifed version of application/libraries/default.rb:

class Chef
  class Provider
    module ApplicationBase

    # ...skip...

      def callback(what, callback_code=nil)
        Chef::Log.debug("Got callback #{what}: #{callback_code.inspect}")
        @collection = Chef::ResourceCollection.new
        case callback_code
        when Proc
          Chef::Log.info "#{@new_resource} running callback #{what}"
          # recipe_eval(&callback_code)
          recipe_eval(&callback_code)
          converge # <--- Remove this line and no callbacks will work.
        when String
          callback_file = "#{release_path}/#{callback_code}"
          unless ::File.exist?(callback_file)
            raise RuntimeError, "Can't find your callback file #{callback_file}"
          end
          run_callback_from_file(callback_file)
        when nil
          nil
        else
          raise RuntimeError, "You gave me a callback I don't know what to do with: #{callback_code.inspect}"
        end
      end
    end
  end
end
like image 741
Aleksei Gusev Avatar asked Nov 12 '22 21:11

Aleksei Gusev


1 Answers

Opscode just confirmed that it is a bug in Chef. If someone needs more details and status of the fix, please use these links:

  • http://tickets.opscode.com/browse/COOK-1747
  • http://tickets.opscode.com/browse/CHEF-3493
like image 164
Aleksei Gusev Avatar answered Nov 15 '22 11:11

Aleksei Gusev