toft-puppet 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/Gemfile +3 -0
  2. data/Gemfile.lock +62 -0
  3. data/Rakefile +121 -0
  4. data/features/checker.feature +14 -0
  5. data/features/chef.feature +70 -0
  6. data/features/command.feature +20 -0
  7. data/features/node.feature +41 -0
  8. data/features/puppet.feature +40 -0
  9. data/features/step_definitions/centos/checks.rb +9 -0
  10. data/features/step_definitions/checker.rb +15 -0
  11. data/features/step_definitions/chef.rb +43 -0
  12. data/features/step_definitions/command.rb +28 -0
  13. data/features/step_definitions/node.rb +65 -0
  14. data/features/step_definitions/puppet.rb +7 -0
  15. data/features/support/env.rb +25 -0
  16. data/fixtures/chef/attributes.json +9 -0
  17. data/fixtures/chef/cookbooks/test/attributes/default.rb +4 -0
  18. data/fixtures/chef/cookbooks/test/recipes/attribute.rb +19 -0
  19. data/fixtures/chef/cookbooks/test/recipes/default.rb +4 -0
  20. data/fixtures/chef/cookbooks/test/recipes/role.rb +4 -0
  21. data/fixtures/chef/roles/test.rb +3 -0
  22. data/fixtures/puppet/conf/fileserver.conf +3 -0
  23. data/fixtures/puppet/conf/puppet.conf +15 -0
  24. data/fixtures/puppet/conf/puppet_exec.conf +9 -0
  25. data/fixtures/puppet/conf/puppet_fileserver.conf +8 -0
  26. data/fixtures/puppet/conf/puppet_modules.conf +7 -0
  27. data/fixtures/puppet/conf/puppet_template.conf +8 -0
  28. data/fixtures/puppet/manifests/fileserver/conf/test_fileserver +1 -0
  29. data/fixtures/puppet/manifests/nodes/test_node.pp +26 -0
  30. data/fixtures/puppet/manifests/site.pp +1 -0
  31. data/fixtures/puppet/manifests/templates/template_test +2 -0
  32. data/fixtures/puppet/manifests/test.pp +8 -0
  33. data/fixtures/puppet/manifests/test_fileserver.pp +14 -0
  34. data/fixtures/puppet/manifests/test_install.pp +5 -0
  35. data/fixtures/puppet/manifests/test_module.pp +5 -0
  36. data/fixtures/puppet/manifests/test_service.pp +11 -0
  37. data/fixtures/puppet/manifests/test_template.pp +12 -0
  38. data/fixtures/puppet/modules/test_module/manifests/init.pp +8 -0
  39. data/lib/toft.rb +39 -0
  40. data/lib/toft/chef/chef_attributes.rb +29 -0
  41. data/lib/toft/chef/chef_runner.rb +77 -0
  42. data/lib/toft/command_executor.rb +16 -0
  43. data/lib/toft/file_checker.rb +47 -0
  44. data/lib/toft/node.rb +243 -0
  45. data/lib/toft/node_controller.rb +32 -0
  46. data/lib/toft/puppet/puppet_runner.rb +38 -0
  47. data/lib/toft/version.rb +3 -0
  48. data/scripts/bin/centos/lxc-prepare-host +172 -0
  49. data/scripts/bin/centos/provision_vagrant +11 -0
  50. data/scripts/bin/share/install-chef-ubuntu.sh +19 -0
  51. data/scripts/bin/share/lxc-create-centos-image +60 -0
  52. data/scripts/bin/ubuntu/lxc-create-ubuntu-image +77 -0
  53. data/scripts/bin/ubuntu/lxc-prepare-host +199 -0
  54. data/scripts/bin/ubuntu/provision_vagrant +9 -0
  55. data/scripts/lxc-templates/files/rc.local +38 -0
  56. data/scripts/lxc-templates/lxc-centos-6 +279 -0
  57. data/scripts/lxc-templates/lxc-lenny +255 -0
  58. data/scripts/lxc-templates/lxc-lucid +313 -0
  59. data/scripts/lxc-templates/lxc-natty +237 -0
  60. data/spec/fixtures/illegal_syntax.json +1 -0
  61. data/spec/spec_helper.rb +6 -0
  62. data/spec/toft/chef/chef_attributes_spec.rb +39 -0
  63. data/spec/toft/chef/chef_runner_spec.rb +34 -0
  64. data/spec/toft/node_spec.rb +18 -0
  65. data/spec/toft/puppet/puppet_runner_spec.rb +26 -0
  66. metadata +234 -0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,62 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ toft (0.0.8)
5
+ net-ssh
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ archive-tar-minitar (0.5.2)
11
+ builder (3.0.0)
12
+ cucumber (1.1.0)
13
+ builder (>= 2.1.2)
14
+ diff-lcs (>= 1.1.2)
15
+ gherkin (~> 2.5.0)
16
+ json (>= 1.4.6)
17
+ term-ansicolor (>= 1.0.6)
18
+ diff-lcs (1.1.3)
19
+ erubis (2.7.0)
20
+ ffi (1.0.9)
21
+ fpm (0.3.10)
22
+ json
23
+ gherkin (2.5.1)
24
+ json (>= 1.4.6)
25
+ i18n (0.6.0)
26
+ json (1.5.4)
27
+ net-scp (1.0.4)
28
+ net-ssh (>= 1.99.1)
29
+ net-ssh (2.1.4)
30
+ rake (0.9.2)
31
+ rspec (2.6.0)
32
+ rspec-core (~> 2.6.0)
33
+ rspec-expectations (~> 2.6.0)
34
+ rspec-mocks (~> 2.6.0)
35
+ rspec-core (2.6.4)
36
+ rspec-expectations (2.6.0)
37
+ diff-lcs (~> 1.1.2)
38
+ rspec-mocks (2.6.0)
39
+ term-ansicolor (1.0.6)
40
+ thor (0.14.6)
41
+ vagrant (0.8.7)
42
+ archive-tar-minitar (= 0.5.2)
43
+ erubis (~> 2.7.0)
44
+ i18n (~> 0.6.0)
45
+ json (~> 1.5.1)
46
+ net-scp (~> 1.0.4)
47
+ net-ssh (~> 2.1.4)
48
+ thor (~> 0.14.6)
49
+ virtualbox (~> 0.9.1)
50
+ virtualbox (0.9.2)
51
+ ffi (~> 1.0.9)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ cucumber
58
+ fpm
59
+ rake
60
+ rspec
61
+ toft!
62
+ vagrant (>= 0.8.7)
data/Rakefile ADDED
@@ -0,0 +1,121 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ PROJECT_ROOT = File.dirname(__FILE__)
4
+ LXC_PACKAGE_NAME = "toft-lxc"
5
+
6
+ desc "clean artifacts"
7
+ task :clean do
8
+ `rm -rf pkg`
9
+ `rm -rf tmp`
10
+ end
11
+
12
+ desc "build gem and scripts package"
13
+ task :package => [:build, :package_deb, :package_rpm]
14
+
15
+ task :package_deb do
16
+ src_dir = "#{PROJECT_ROOT}/scripts"
17
+ content_dir = "#{PROJECT_ROOT}/pkg/#{LXC_PACKAGE_NAME}"
18
+ mkdir_p content_dir
19
+ mkdir_p "#{content_dir}/usr/bin"
20
+ mkdir_p "#{content_dir}/var/cache/lxc"
21
+ mkdir_p "#{content_dir}/usr/lib/lxc/templates"
22
+ cp_r Dir.glob("#{src_dir}/bin/share/*"), "#{content_dir}/usr/bin"
23
+ cp_r Dir.glob("#{src_dir}/bin/ubuntu/*"), "#{content_dir}/usr/bin"
24
+ cp_r Dir.glob("#{src_dir}/lxc-templates/*"), "#{content_dir}/usr/lib/lxc/templates"
25
+
26
+ post_install_script = <<-eos
27
+ #!/bin/sh -e
28
+ /usr/bin/lxc-prepare-host
29
+ eos
30
+ File.open("#{PROJECT_ROOT}/pkg/toft-lxc-post-install.sh", 'w') { |f| f.write(post_install_script) }
31
+
32
+ Dir.chdir("pkg") do
33
+ system <<-EOF
34
+ fpm -s dir \
35
+ -t deb \
36
+ -C #{content_dir} \
37
+ -a all \
38
+ -n #{LXC_PACKAGE_NAME} \
39
+ -v #{Toft::VERSION} \
40
+ -m "Huang Liang<exceedhl@gmail.com>" \
41
+ --description "lxc templates and helper provided by toft" \
42
+ -d sudo \
43
+ -d rpm \
44
+ -d dnsutils \
45
+ -d lxc \
46
+ -d bridge-utils \
47
+ -d debootstrap \
48
+ -d dhcp3-server \
49
+ -d bind9 \
50
+ -d ntp \
51
+ --replaces lxc \
52
+ --conflicts apparmor \
53
+ --conflicts apparmor-utils \
54
+ --post-install "#{PROJECT_ROOT}/pkg/toft-lxc-post-install.sh" \
55
+ .
56
+ EOF
57
+ end
58
+ end
59
+
60
+ task :package_rpm do
61
+ src_dir = "#{PROJECT_ROOT}/scripts"
62
+ content_dir = "#{PROJECT_ROOT}/pkg/#{LXC_PACKAGE_NAME}"
63
+ mkdir_p content_dir
64
+ mkdir_p "#{content_dir}/usr/bin"
65
+ mkdir_p "#{content_dir}/var/lib/lxc"
66
+ mkdir_p "#{content_dir}/var/cache/lxc"
67
+ mkdir_p "#{content_dir}/usr/lib/lxc/templates"
68
+ cp_r Dir.glob("#{src_dir}/bin/share/*"), "#{content_dir}/usr/bin"
69
+ cp_r Dir.glob("#{src_dir}/bin/centos/*"), "#{content_dir}/usr/bin"
70
+ cp_r Dir.glob("#{src_dir}/lxc-templates/*"), "#{content_dir}/usr/lib/lxc/templates"
71
+
72
+ pre_install_script = <<-eos
73
+ #!/bin/sh -e
74
+ # intsall lxc if not exist
75
+ if [[ ! -f /usr/bin/lxc-ls ]]; then
76
+ (cd /tmp && \
77
+ wget http://lxc.sourceforge.net/download/lxc/lxc-0.7.4.tar.gz && \
78
+ tar zxf lxc-0.7.4.tar.gz && \
79
+ cd lxc-0.7.4 && \
80
+ ./configure --prefix=/usr --with-config-path=/var/lib/lxc && \
81
+ make && \
82
+ make install)
83
+ fi
84
+ eos
85
+
86
+ post_install_script = <<-eos
87
+ #!/bin/sh -e
88
+ /usr/bin/lxc-prepare-host
89
+ eos
90
+ File.open("#{PROJECT_ROOT}/pkg/toft-lxc-pre-install.sh", 'w') { |f| f.write(pre_install_script) }
91
+ File.open("#{PROJECT_ROOT}/pkg/toft-lxc-post-install.sh", 'w') { |f| f.write(post_install_script) }
92
+
93
+ Dir.chdir("pkg") do
94
+ system <<-EOF
95
+ fpm -s dir \
96
+ -t rpm \
97
+ -C #{content_dir} \
98
+ -a all \
99
+ -n #{LXC_PACKAGE_NAME} \
100
+ -v #{Toft::VERSION} \
101
+ -m "Huang Liang<exceedhl@gmail.com>" \
102
+ --description "lxc templates and helper provided by toft" \
103
+ -d sudo \
104
+ -d bind-utils \
105
+ -d bridge-utils \
106
+ -d dhcp \
107
+ -d bind \
108
+ -d ntp \
109
+ -d libcap-devel \
110
+ --post-install "#{PROJECT_ROOT}/pkg/toft-lxc-post-install.sh" \
111
+ --pre-install "#{PROJECT_ROOT}/pkg/toft-lxc-pre-install.sh" \
112
+ .
113
+ EOF
114
+ end
115
+ end
116
+
117
+ desc "run all tests and features"
118
+ task :test do
119
+ `rspec spec`
120
+ `sudo cucumber features`
121
+ end
@@ -0,0 +1,14 @@
1
+ Feature: Checkers provided by Toft to help you verify system state
2
+
3
+ Scenario: Dir checker
4
+ Given I have a clean running node n1
5
+ Then Node "n1" should have "directory" "/tmp" owned by user "root" and group "root" with permission "1777"
6
+ Then Node "n1" should have not file or directory "/non-exist-dir"
7
+ Then Node "n1" should have file or directory "tmp"
8
+
9
+ Scenario: File checker
10
+ Given I have a clean running node n1
11
+ When Running ssh command "if getent passwd n1; then userdel -fr n1; fi; useradd -m n1" on "n1" should succeed
12
+ And Running ssh command "sudo -u n1 touch /tmp/a" on "n1" should succeed
13
+ Then Node "n1" should have file or directory "/tmp/a"
14
+ And Node "n1" should have "regular empty file" "/tmp/a" owned by user "n1" and group "n1" with permission "644"
@@ -0,0 +1,70 @@
1
+ Feature: Chef support
2
+
3
+ Scenario: Run chef recipe on nodes
4
+ Given I have a clean running node n1
5
+ When I run "recipe[test]" on node "n1"
6
+ Then Node "n1" should have file or directory "/tmp/stub/dir"
7
+
8
+ Scenario: Run chef recipe with attributes
9
+ Given I have a clean running node n1
10
+ When I run "recipe[test::attribute]" on node "n1" and overwrite attributes with:
11
+ |key|value|
12
+ |one|one|
13
+ |two.one|two_one|
14
+ |two.two|two_two|
15
+ |three|three|
16
+ Then Node "n1" should have file or directory "/tmp/stub/one"
17
+ Then Node "n1" should have file or directory "/tmp/stub/two_one"
18
+ Then Node "n1" should have file or directory "/tmp/stub/two_two"
19
+ Then Node "n1" should have file or directory "/tmp/stub/three"
20
+
21
+ Scenario: Run multiple chef recipes
22
+ Given I have a clean running node n1
23
+ When I run recipes on node "n1":
24
+ |recipe|
25
+ |recipe[test::role]|
26
+ |recipe[test]|
27
+ Then Node "n1" should have file or directory "/tmp/stub/dir"
28
+ Then Node "n1" should have file or directory "/tmp/stub/role"
29
+
30
+ Scenario: Run chef role
31
+ Given I have a clean running node n1
32
+ When I run "role[test]" on node "n1"
33
+ Then Node "n1" should have file or directory "/tmp/stub/role"
34
+
35
+ Scenario: Toft should not deal with empty cookbook and role path
36
+ Given I have a clean running node n1
37
+ When I set the role path to empty
38
+ Then Running chef "recipe[test]" on node "n1" should succeed
39
+ When I set the cookbook path to empty
40
+ Then Running chef "recipe[test]" on node "n1" should fail
41
+
42
+ Scenario: Run chef recipe with json attributes file
43
+ Given I have a clean running node n1
44
+ When I run "recipe[test::attribute]" on node "n1" and overwrite attributes with json file "attributes.json"
45
+ Then Node "n1" should have file or directory "/tmp/stub/one"
46
+ Then Node "n1" should have file or directory "/tmp/stub/two_one"
47
+ Then Node "n1" should have file or directory "/tmp/stub/two_two"
48
+ Then Node "n1" should have file or directory "/tmp/stub/three"
49
+
50
+ Scenario: Attributes table should override attributes in json file
51
+ Given I have a clean running node n1
52
+ When I run "recipe[test::attribute]" on node "n1" and overwrite attributes with json file "attributes.json" and chef attributes:
53
+ |key|value|
54
+ |one|override|
55
+ Then Node "n1" should have file or directory "/tmp/stub/override"
56
+ Then Node "n1" should have file or directory "/tmp/stub/two_one"
57
+ Then Node "n1" should have file or directory "/tmp/stub/two_two"
58
+ Then Node "n1" should have file or directory "/tmp/stub/three"
59
+
60
+ Scenario: Run non-exist recipe
61
+
62
+ Scenario: Run non-exist role
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
@@ -0,0 +1,20 @@
1
+ Feature: Run ssh command on node
2
+
3
+ Scenario: Run command on node successfully
4
+ Given I have a clean running node n1
5
+ Then Running ssh command "" on "n1" should fail
6
+ And Running ssh command "ps" on "n1" should succeed
7
+ And Running ssh command "non-exist-command" on "n1" should fail
8
+ And Running ssh command "netstat -nr" on "n1" should succeed
9
+
10
+ Scenario: Test rm
11
+ Given I have a clean running node n1
12
+ Then Rm "" on "n1" should fail
13
+ And Rm "tmp/*" on "n1" should fail
14
+ And Rm "/tmp/*" on "n1" should succeed
15
+
16
+ Scenario: Check ssh command result
17
+ Given I have a clean running node n1
18
+ Then the result of running ssh command "ps" on "n1" should contain "sshd"
19
+ Then the result of running ssh command "chef-solo" on "n1" should fail because of "No cookbook found"
20
+
@@ -0,0 +1,41 @@
1
+ Feature: Node management
2
+
3
+ Scenario: Start or stop node
4
+ Given I have a clean running node n1
5
+ Then the node "n1" should be running
6
+ When I stop node "n1"
7
+ Then the node "n1" should be stopped
8
+ When I start node "n1"
9
+ Then the node "n1" should be running
10
+
11
+ Scenario: Add and remove cnames for a node
12
+ Given I have a clean running node n1
13
+ And I add another node "n2"
14
+ When I add cname "cn1" to "n1"
15
+ Then Running ssh command "ping -c 1 cn1" on "n2" should succeed
16
+ When I remove cname "cn1" from "n1"
17
+ Then Running ssh command "ping -c 1 cn1" on "n2" should fail
18
+ And Node "n2" is destroyed
19
+
20
+ Scenario: Create node only by name and fetch their info
21
+ Given I have a clean running node n1
22
+ When I add another node "n3"
23
+ Then Running ssh command "ping -c 1 n1" on "n3" should succeed
24
+ And Running ssh command "ping -c 1 n3" on "n1" should succeed
25
+ And Node "n1" should have ip address same with that obtained from inside it through ssh
26
+ And Node "n3" should have ip address same with that obtained from inside it through ssh
27
+ And Hostname of Node "n1" should match its name
28
+ And Node "n3" is destroyed
29
+
30
+ Scenario: Create or destroy node
31
+ Given I have a clean running node n1
32
+ Then There should be 1 nodes in the environment
33
+ When I add another node "n2" with ip "192.168.20.3"
34
+ Then There should be 2 nodes in the environment
35
+ When I destroy node "n2"
36
+ Then There should be 1 nodes in the environment
37
+
38
+ Scenario: Change hostname used internally for a specific host
39
+ Given I have a clean running node n1
40
+ And I change the internal hostname for "n1" to "correct.puppet.com"
41
+ Then the result of running ssh command "hostname" on "n1" should contain "correct.puppet.com"
@@ -0,0 +1,40 @@
1
+ Feature: Puppet support
2
+
3
+ Scenario: Run Puppet manifest on nodes
4
+ Given I have a clean running node n1
5
+ When I run puppet manifest "test.pp" on node "n1"
6
+ Then Node "n1" should have file or directory "/tmp/puppet_test"
7
+
8
+ Scenario: Run puppet manifest with included nodes
9
+ Given I have a clean running node n1
10
+ And I change the internal hostname for "n1" to "correct.puppet.com"
11
+ And I run puppet manifest "site.pp" on node "n1"
12
+ Then Node "n1" should have file or directory "/tmp/puppet_test_correct"
13
+ And Node "n1" should have file or directory "/tmp/puppet_test_default"
14
+ And Node "n1" should have not file or directory "/tmp/puppet_test_incorrect"
15
+
16
+ Scenario: Run puppet manifest with modules
17
+ Given I have a clean running node n1
18
+ When I run puppet manifest "test_module.pp" with config file "puppet_modules.conf" on node "n1"
19
+ Then Node "n1" should have file or directory "/tmp/puppet_test_module"
20
+
21
+ Scenario: Run puppet manifest with static files being served by fileserver
22
+ Given I have a clean running node n1
23
+ When I run puppet manifest "test_fileserver.pp" with config file "puppet_fileserver.conf" on node "n1"
24
+ Then Node "n1" should have file or directory "/tmp/puppet_test_fileserver"
25
+
26
+ Scenario: Run puppet manifest with template dir configuration
27
+ Given I have a clean running node n1
28
+ When I run puppet manifest "test_template.pp" with config file "puppet_template.conf" on node "n1"
29
+ Then Node "n1" should have file or directory "/tmp/puppet_test_template"
30
+
31
+ Scenario: Check that package was installed on centos box
32
+ Given I have a clean running node n1
33
+ When I run puppet manifest "test_install.pp" on node "n1"
34
+ Then Node "n1" should have package "zip" installed in the centos box
35
+
36
+ Scenario: Check that service is running on centos box
37
+ Given I have a clean running node n1
38
+ When I run puppet manifest "test_service.pp" on node "n1"
39
+ Then Node "n1" should have service "named" running in the centos box
40
+
@@ -0,0 +1,9 @@
1
+ Then /^Node "([^"]*)" should have package "([^"]*)" installed in the centos box$/ do |node, package|
2
+ result = find(node).run_ssh("rpm -qa #{package}")
3
+ result.stdout.should include(package)
4
+ end
5
+
6
+ Then /^Node "([^"]*)" should have service "([^"]*)" running in the centos box$/ do |node, service|
7
+ result = find(node).run_ssh("ps -ef | grep -v grep | grep #{service} | wc -l")
8
+ result.stdout.strip!.should == "1"
9
+ end
@@ -0,0 +1,15 @@
1
+ Then /^Node "([^"]*)" should have not file or directory "([^"]*)"$/ do |node, dirpath|
2
+ find(node).file(dirpath).should_not be_exist
3
+ end
4
+
5
+ Then /^Node "([^"]*)" should have file or directory "([^"]*)"$/ do |node, dirpath|
6
+ find(node).file(dirpath).should be_exist
7
+ end
8
+
9
+ Then /^Node "([^"]*)" should have "([^"]*)" "([^"]*)" owned by user "([^"]*)" and group "([^"]*)" with permission "([^"]*)"$/ do |node, type, dirpath, user, group, mode|
10
+ file = find(node).file(dirpath)
11
+ file.filetype.should == type
12
+ file.owner.should == user
13
+ file.group.should == group
14
+ file.mode.should == mode
15
+ end
@@ -0,0 +1,43 @@
1
+ When /^I run "([^"]*)" on node "([^"]*)"$/ do |run_list, node|
2
+ find(node).run_chef run_list
3
+ end
4
+
5
+ When /^I run recipes on node "([^"]*)":$/ do |node, recipes_table|
6
+ recipes = []
7
+ recipes_table.hashes.each do |row|
8
+ recipes << row[:recipe]
9
+ end
10
+ find(node).run_chef recipes
11
+ end
12
+
13
+ When /^I run "([^"]*)" on node "([^"]*)" and overwrite attributes with:$/ do |run_list, node, table|
14
+ find(node).run_chef run_list, {:attributes => Toft::ChefAttributes.new(table)}
15
+ end
16
+
17
+ When /^I set the role path to empty$/ do
18
+ Toft.role_path = ""
19
+ @n1.rm "/tmp/*"
20
+ end
21
+
22
+ Then /^Running chef "([^"]*)" on node "([^"]*)" should succeed$/ do |run_list, node|
23
+ result = false
24
+ lambda { result = find(node).run_chef(run_list) }.should_not raise_error
25
+ result.should be_true
26
+ end
27
+
28
+ When /^I set the cookbook path to empty$/ do
29
+ Toft.cookbook_path = ""
30
+ @n1.rm "/tmp/*"
31
+ end
32
+
33
+ Then /^Running chef "([^"]*)" on node "([^"]*)" should fail$/ do |run_list, node|
34
+ lambda { find(node).run_chef(run_list) }.should raise_error
35
+ end
36
+
37
+ When /^I run "([^"]*)" on node "([^"]*)" and overwrite attributes with json file "([^"]*)"$/ do |run_list, node, json_file|
38
+ find(node).run_chef run_list, :json => CHEF_FIXTURE_PATH + '/attributes.json'
39
+ end
40
+
41
+ When /^I run "([^"]*)" on node "([^"]*)" and overwrite attributes with json file "([^"]*)" and chef attributes:$/ do |run_list, node, json_file, table|
42
+ find(node).run_chef run_list, {:json => CHEF_FIXTURE_PATH + '/attributes.json', :attributes => Toft::ChefAttributes.new(table)}
43
+ end