Browse Source

Merge pull request #21 from andreacampi/COOK-1673

[COOK-1673] Fix callbacks on Chef 10.14.x
Joshua Timberman 11 years ago
parent
commit
7cecac7ff5

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+.bundle
+.cache
+.kitchen
+bin

+ 10 - 0
Gemfile

@@ -0,0 +1,10 @@
+source :rubygems
+
+gem 'cucumber', '~> 1.2.1'
+gem 'httparty', '~> 0.8.3'
+gem 'minitest', '~> 3.0.0'
+gem 'nokogiri', '~> 1.5.0'
+
+group :kitchen  do
+  gem 'test-kitchen'
+end

+ 132 - 0
Gemfile.lock

@@ -0,0 +1,132 @@
+GEM
+  remote: http://rubygems.org/
+  specs:
+    archive-tar-minitar (0.5.2)
+    builder (3.1.3)
+    bunny (0.7.9)
+    chef (10.14.2)
+      bunny (>= 0.6.0, < 0.8.0)
+      erubis
+      highline (>= 1.6.9)
+      json (>= 1.4.4, <= 1.6.1)
+      mixlib-authentication (>= 1.3.0)
+      mixlib-cli (>= 1.1.0)
+      mixlib-config (>= 1.1.2)
+      mixlib-log (>= 1.3.0)
+      mixlib-shellout
+      moneta
+      net-ssh (~> 2.2.2)
+      net-ssh-multi (~> 1.1.0)
+      ohai (>= 0.6.0)
+      rest-client (>= 1.0.4, < 1.7.0)
+      treetop (~> 1.4.9)
+      uuidtools
+      yajl-ruby (~> 1.1)
+    childprocess (0.3.5)
+      ffi (~> 1.0, >= 1.0.6)
+    coderay (1.0.7)
+    cucumber (1.2.1)
+      builder (>= 2.1.2)
+      diff-lcs (>= 1.1.3)
+      gherkin (~> 2.11.0)
+      json (>= 1.4.6)
+    diff-lcs (1.1.3)
+    erubis (2.7.0)
+    ffi (1.1.5)
+    foodcritic (1.6.1)
+      erubis
+      gherkin (~> 2.11.1)
+      gist (~> 3.1.0)
+      nokogiri (= 1.5.0)
+      pry (~> 0.9.8.4)
+      rak (~> 1.4)
+      treetop (~> 1.4.10)
+      yajl-ruby (~> 1.1.0)
+    gherkin (2.11.2)
+      json (>= 1.4.6)
+    gist (3.1.0)
+    hashr (0.0.22)
+    highline (1.6.15)
+    httparty (0.8.3)
+      multi_json (~> 1.0)
+      multi_xml
+    i18n (0.6.1)
+    ipaddress (0.8.0)
+    json (1.5.4)
+    librarian (0.0.24)
+      archive-tar-minitar (>= 0.5.2)
+      chef (>= 0.10)
+      highline
+      thor (~> 0.15)
+    log4r (1.1.10)
+    method_source (0.7.1)
+    mime-types (1.19)
+    minitest (3.0.1)
+    mixlib-authentication (1.3.0)
+      mixlib-log
+    mixlib-cli (1.2.2)
+    mixlib-config (1.1.2)
+    mixlib-log (1.4.1)
+    mixlib-shellout (1.1.0)
+    moneta (0.6.0)
+    multi_json (1.3.6)
+    multi_xml (0.5.1)
+    net-scp (1.0.4)
+      net-ssh (>= 1.99.1)
+    net-ssh (2.2.2)
+    net-ssh-gateway (1.1.0)
+      net-ssh (>= 1.99.1)
+    net-ssh-multi (1.1)
+      net-ssh (>= 2.1.4)
+      net-ssh-gateway (>= 0.99.0)
+    nokogiri (1.5.0)
+    ohai (6.14.0)
+      ipaddress
+      mixlib-cli
+      mixlib-config
+      mixlib-log
+      systemu
+      yajl-ruby
+    polyglot (0.3.3)
+    pry (0.9.8.4)
+      coderay (~> 1.0.5)
+      method_source (~> 0.7.1)
+      slop (>= 2.4.4, < 3)
+    rak (1.4)
+    rest-client (1.6.7)
+      mime-types (>= 1.16)
+    slop (2.4.4)
+    systemu (2.5.2)
+    test-kitchen (0.5.4)
+      foodcritic (~> 1.4)
+      hashr (~> 0.0.20)
+      highline (>= 1.6.9)
+      librarian (~> 0.0.20)
+      mixlib-cli (~> 1.2.2)
+      vagrant (~> 1.0.2)
+      yajl-ruby (~> 1.1.0)
+    thor (0.16.0)
+    treetop (1.4.10)
+      polyglot
+      polyglot (>= 0.3.1)
+    uuidtools (2.1.3)
+    vagrant (1.0.5)
+      archive-tar-minitar (= 0.5.2)
+      childprocess (~> 0.3.1)
+      erubis (~> 2.7.0)
+      i18n (~> 0.6.0)
+      json (~> 1.5.1)
+      log4r (~> 1.1.9)
+      net-scp (~> 1.0.4)
+      net-ssh (~> 2.2.2)
+    yajl-ruby (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  cucumber (~> 1.2.1)
+  httparty (~> 0.8.3)
+  minitest (~> 3.0.0)
+  nokogiri (~> 1.5.0)
+  test-kitchen

+ 12 - 3
libraries/default.rb

@@ -135,7 +135,12 @@ class Chef
 
       def deploy_provider
         @deploy_provider ||= begin
-          deploy_provider = Chef::Platform.provider_for_resource(@deploy_resource)
+          version = Chef::Version.new(Chef::VERSION)
+          deploy_provider = if version.major > 10 || version.minor >= 14
+            Chef::Platform.provider_for_resource(@deploy_resource, :nothing)
+          else
+            Chef::Platform.provider_for_resource(@deploy_resource)
+          end
           deploy_provider.load_current_resource
           deploy_provider
         end
@@ -155,7 +160,7 @@ class Chef
         case callback_code
         when Proc
           Chef::Log.info "#{@new_resource} running callback #{what}"
-          recipe_eval(&callback_code)
+          safe_recipe_eval(&callback_code)
         when String
           callback_file = "#{release_path}/#{callback_code}"
           unless ::File.exist?(callback_file)
@@ -173,11 +178,15 @@ class Chef
         if ::File.exist?(callback_file)
           Dir.chdir(release_path) do
             Chef::Log.info "#{@new_resource} running deploy hook #{callback_file}"
-            recipe_eval { from_file(callback_file) }
+            safe_recipe_eval { from_file(callback_file) }
           end
         end
       end
 
+      def safe_recipe_eval(&callback_code)
+        recipe_eval(&callback_code)
+        converge if respond_to?(:converge)
+      end
     end
   end
 end

+ 6 - 1
providers/default.rb

@@ -140,7 +140,12 @@ def run_deploy(force = false)
       ([new_resource]+new_resource.sub_resources).each do |res|
         cmd = res.restart_command
         if cmd.is_a? Proc
-          provider = Chef::Platform.provider_for_resource(res)
+          version = Chef::Version.new(Chef::VERSION)
+          provider = if version.major > 10 || version.minor >= 14
+            Chef::Platform.provider_for_resource(res, :nothing)
+          else
+            Chef::Platform.provider_for_resource(res)
+          end
           provider.load_current_resource
           provider.instance_eval(&cmd)
         elsif cmd && !cmd.empty?

+ 14 - 0
test/features/basic_app.feature

@@ -0,0 +1,14 @@
+@basic_app
+Feature: Deploy a basic app
+
+In order to run my application
+As a developer
+I want to deploy a basic application
+
+  Scenario: Deploy a basic app
+    Given a new server
+    Then the "/var/www/basic_app" directory should exist
+    And the "/var/www/basic_app/shared" directory should exist
+    And the "/var/www/basic_app/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f" directory should exist
+    And it should be owned by nobody with group daemon
+    And "/var/www/basic_app/current" should be a symlink to "/var/www/basic_app/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"

+ 27 - 0
test/features/block_callbacks.feature

@@ -0,0 +1,27 @@
+@block_callbacks
+Feature: Run block callbacks
+
+In order to write my application recipe
+As a recipe developer
+I want my callbacks to be called
+
+  Scenario: Deploy a basic app
+    Given a new server
+    Then the "/var/www/block_callbacks" directory should exist
+    And the "/var/www/block_callbacks/shared" directory should exist
+    And the "/var/www/block_callbacks/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f" directory should exist
+    And the "/tmp/block_callbacks/before_deploy" file should exist
+    And it should contain a line matching "release_path /var/www/block_callbacks/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"
+    And it should contain a line matching "shared_path /var/www/block_callbacks/shared"
+    And the "/tmp/block_callbacks/before_migrate" file should exist
+    And it should contain a line matching "release_path /var/www/block_callbacks/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"
+    And it should contain a line matching "shared_path /var/www/block_callbacks/shared"
+    And the "/tmp/block_callbacks/before_symlink" file should exist
+    And it should contain a line matching "release_path /var/www/block_callbacks/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"
+    And it should contain a line matching "shared_path /var/www/block_callbacks/shared"
+    And the "/tmp/block_callbacks/before_restart" file should exist
+    And it should contain a line matching "release_path /var/www/block_callbacks/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"
+    And it should contain a line matching "shared_path /var/www/block_callbacks/shared"
+    And the "/tmp/block_callbacks/after_restart" file should exist
+    And it should contain a line matching "release_path /var/www/block_callbacks/releases/0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"
+    And it should contain a line matching "shared_path /var/www/block_callbacks/shared"

+ 24 - 0
test/features/file_callbacks.feature

@@ -0,0 +1,24 @@
+@file_callbacks
+Feature: Run file callbacks
+
+In order to write my application recipe
+As a recipe developer
+I want my callbacks to be called
+
+  Scenario: Deploy a basic app
+    Given a new server
+    Then the "/var/www/file_callbacks" directory should exist
+    And the "/var/www/file_callbacks/shared" directory should exist
+    And the "/var/www/file_callbacks/releases/7cfe06bf4d245264e9d3ec88b54da9d275fe9174" directory should exist
+    And the "/tmp/file_callbacks/before_migrate" file should exist
+    And it should contain a line matching "release_path /var/www/file_callbacks/releases/7cfe06bf4d245264e9d3ec88b54da9d275fe9174"
+    And it should contain a line matching "shared_path /var/www/file_callbacks/shared"
+    And the "/tmp/file_callbacks/before_symlink" file should exist
+    And it should contain a line matching "release_path /var/www/file_callbacks/releases/7cfe06bf4d245264e9d3ec88b54da9d275fe9174"
+    And it should contain a line matching "shared_path /var/www/file_callbacks/shared"
+    And the "/tmp/file_callbacks/before_restart" file should exist
+    And it should contain a line matching "release_path /var/www/file_callbacks/releases/7cfe06bf4d245264e9d3ec88b54da9d275fe9174"
+    And it should contain a line matching "shared_path /var/www/file_callbacks/shared"
+    And the "/tmp/file_callbacks/after_restart" file should exist
+    And it should contain a line matching "release_path /var/www/file_callbacks/releases/7cfe06bf4d245264e9d3ec88b54da9d275fe9174"
+    And it should contain a line matching "shared_path /var/www/file_callbacks/shared"

+ 27 - 0
test/features/step_definitions/app_steps.rb

@@ -0,0 +1,27 @@
+Given /^a new server$/ do
+end
+
+Then /^the "?(.+?)"? directory should exist$/ do |dir_name|
+  @dir_name = dir_name
+  assert File.directory?(dir_name), "File.directory?(#{dir_name}) = #{File.directory?(dir_name)}"
+end
+
+Then /^the "?(.+?)"? file should exist$/ do |file_name|
+  @file_name = file_name
+  assert File.file?(file_name)
+end
+
+Then /^it should be owned by (.+?) with group (.+?)$/ do |owner, group|
+  # TODO
+end
+
+Then /^"?(.+?)"? should be a symlink to "?(.+?)"$/ do |link, target|
+  assert File.symlink?(link)
+  assert_equal target, File.readlink(link)
+end
+
+Then /^it should contain a line matching "(.+?)"$/ do |regexp|
+  content = File.open(@file_name).read
+  re = Regexp.new("^#{regexp}$")
+  assert content =~ re
+end

+ 3 - 0
test/features/support/env.rb

@@ -0,0 +1,3 @@
+require 'minitest/spec'
+World(MiniTest::Assertions)
+MiniTest::Spec.new(nil)

+ 7 - 0
test/kitchen/Kitchenfile

@@ -0,0 +1,7 @@
+cookbook "application" do
+  configuration "basic_app"
+  configuration "block_callbacks"
+  configuration "file_callbacks"
+  lint false                  # XXX
+  run_list_extras ['application_test::setup']
+end

+ 12 - 0
test/kitchen/cookbooks/application_test/CHANGELOG.md

@@ -0,0 +1,12 @@
+# CHANGELOG for application_test
+
+This file is used to list changes made in each version of application_test.
+
+## 0.1.0:
+
+* Initial release of application_test
+
+- - - 
+Check the [Markdown Syntax Guide](http://daringfireball.net/projects/markdown/syntax) for help with Markdown.
+
+The [Github Flavored Markdown page](http://github.github.com/github-flavored-markdown/) describes the differences between markdown on github and standard markdown.

+ 12 - 0
test/kitchen/cookbooks/application_test/README.md

@@ -0,0 +1,12 @@
+Description
+===========
+
+Requirements
+============
+
+Attributes
+==========
+
+Usage
+=====
+

+ 22 - 0
test/kitchen/cookbooks/application_test/attributes/default.rb

@@ -0,0 +1,22 @@
+#
+# Cookbook Name:: application_test
+# Attributes:: default
+#
+# Copyright 2012, ZephirWorks
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+default['application_test']['root_dir'] = '/var/www'
+default['application_test']['owner']    = 'nobody'
+default['application_test']['group']    = 'daemon'

+ 37 - 0
test/kitchen/cookbooks/application_test/libraries/test_setup.rb

@@ -0,0 +1,37 @@
+#
+# Cookbook Name:: application_test
+# Library:: test_setup
+#
+# Copyright 2012, ZephirWorks
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'fileutils'
+
+def remove_app(app_name)
+  app_dir = "#{node['application_test']['root_dir']}/#{app_name}"
+  rev_path = "/tmp/vagrant-chef-1/revision-deploys/#{app_name}"
+
+  FileUtils.rm_rf(app_dir)
+  FileUtils.rm(rev_path) if File.exists?(rev_path)
+end
+
+def test_results(app_name)
+  tmp_dir = "/tmp/#{app_name}"
+
+  FileUtils.rm_rf(tmp_dir)
+  FileUtils.mkdir_p(tmp_dir)
+
+  tmp_dir
+end

+ 10 - 0
test/kitchen/cookbooks/application_test/metadata.rb

@@ -0,0 +1,10 @@
+maintainer       "ZephirWorks"
+maintainer_email "andrea.campi@zephirworks.com"
+license          "Apache 2.0"
+description      "Acceptance tests for application"
+long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
+version          "0.1.0"
+
+%w{application rvm}.each do |cb|
+  depends cb
+end

+ 31 - 0
test/kitchen/cookbooks/application_test/recipes/basic_app.rb

@@ -0,0 +1,31 @@
+#
+# Cookbook Name:: application_test
+# Recipe:: basic_app
+#
+# Copyright 2012, ZephirWorks
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+app_name = "basic_app"
+app_dir = "#{node['application_test']['root_dir']}/#{app_name}"
+
+remove_app(app_name)
+
+application app_name do
+  repository  "https://github.com/h5bp/html5-boilerplate.git"
+  revision    "0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"  # v4.0.0 tag
+  path        app_dir
+  owner       node['application_test']['owner']
+  group       node['application_test']['group']
+end

+ 48 - 0
test/kitchen/cookbooks/application_test/recipes/block_callbacks.rb

@@ -0,0 +1,48 @@
+#
+# Cookbook Name:: application_test
+# Recipe:: block_callbacks
+#
+# Copyright 2012, ZephirWorks
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+app_name = "block_callbacks"
+app_dir = "#{node['application_test']['root_dir']}/#{app_name}"
+
+remove_app(app_name)
+tmp_dir = test_results(app_name)
+
+application app_name do
+  repository  "https://github.com/h5bp/html5-boilerplate.git"
+  revision    "0b60046431d14b6615d53ae6d8bd0ac62ae3eb6f"  # v4.0.0 tag
+  path        app_dir
+  owner       node['application_test']['owner']
+  group       node['application_test']['group']
+
+  #
+  # All these hooks should be invoked with the same context
+  #
+  %w[before_deploy before_migrate before_symlink before_restart after_restart].each do |hook_name|
+    send(hook_name) do # invoke the hook by name
+      resource = @new_resource
+
+      template "#{tmp_dir}/#{hook_name}" do
+        source "hooks.erb"
+        mode 0644
+        variables(:release_path => resource.release_path,
+                  :shared_path  => resource.shared_path)
+      end
+    end
+  end
+end

+ 18 - 0
test/kitchen/cookbooks/application_test/recipes/default.rb

@@ -0,0 +1,18 @@
+#
+# Cookbook Name:: application_test
+# Recipe:: default
+#
+# Copyright 2012, ZephirWorks
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#

+ 39 - 0
test/kitchen/cookbooks/application_test/recipes/file_callbacks.rb

@@ -0,0 +1,39 @@
+#
+# Cookbook Name:: application_test
+# Recipe:: file_callbacks
+#
+# Copyright 2012, ZephirWorks
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+app_name = "file_callbacks"
+app_dir = "#{node['application_test']['root_dir']}/#{app_name}"
+
+remove_app(app_name)
+tmp_dir = test_results(app_name)
+
+application app_name do
+  repository  "https://github.com/andreacampi/rails-app-for-chef-tests.git"
+  revision    "master"
+  path        app_dir
+  owner       node['application_test']['owner']
+  group       node['application_test']['group']
+
+  #
+  # All these hooks should be invoked with the same context
+  #
+  %w[before_migrate before_symlink before_restart after_restart].each do |hook_name|
+    send(hook_name, "chef-hooks/#{hook_name}.rb")
+  end
+end

+ 22 - 0
test/kitchen/cookbooks/application_test/recipes/setup.rb

@@ -0,0 +1,22 @@
+case node.platform
+  when 'ubuntu'
+    %w{libxml2 libxml2-dev libxslt1-dev}.each do |pkg|
+      package pkg do
+        action :install
+      end
+    end
+  when 'centos'
+    %w{libxml2 libxml2-devel libxslt libxslt-devel}.each do |pkg|
+      package pkg do
+        action :install
+      end
+    end
+end
+
+node.set['rvm']['user_installs'] = [
+  { 'user'          => 'vagrant',
+    'default_ruby'  => 'ruby-1.9.2-p320',
+    'rubies'        => [] 
+  }
+]
+include_recipe "rvm::user"

+ 2 - 0
test/kitchen/cookbooks/application_test/templates/default/hooks.erb

@@ -0,0 +1,2 @@
+release_path <%= @release_path %>
+shared_path <%= @shared_path %>