pantry-chef 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.travis.yml +16 -0
  4. data/Gemfile +15 -0
  5. data/LICENSE +20 -0
  6. data/README.md +49 -0
  7. data/Rakefile +18 -0
  8. data/lib/pantry/chef.rb +47 -0
  9. data/lib/pantry/chef/configure_chef.rb +59 -0
  10. data/lib/pantry/chef/list_cookbooks.rb +31 -0
  11. data/lib/pantry/chef/run.rb +30 -0
  12. data/lib/pantry/chef/run_chef_solo.rb +21 -0
  13. data/lib/pantry/chef/send_cookbooks.rb +23 -0
  14. data/lib/pantry/chef/sync_cookbooks.rb +84 -0
  15. data/lib/pantry/chef/sync_data_bags.rb +19 -0
  16. data/lib/pantry/chef/sync_environments.rb +19 -0
  17. data/lib/pantry/chef/sync_roles.rb +19 -0
  18. data/lib/pantry/chef/upload_cookbook.rb +110 -0
  19. data/lib/pantry/chef/upload_data_bag.rb +37 -0
  20. data/lib/pantry/chef/upload_environment.rb +28 -0
  21. data/lib/pantry/chef/upload_role.rb +28 -0
  22. data/lib/pantry/chef/version.rb +5 -0
  23. data/lib/pantry/init.rb +1 -0
  24. data/pantry-chef.gemspec +27 -0
  25. data/test/acceptance/chef/run_test.rb +69 -0
  26. data/test/acceptance/chef/upload_cookbook_test.rb +26 -0
  27. data/test/acceptance/chef/upload_data_bag_test.rb +36 -0
  28. data/test/acceptance/chef/upload_environment_test.rb +22 -0
  29. data/test/acceptance/chef/upload_role_test.rb +21 -0
  30. data/test/acceptance/test_helper.rb +25 -0
  31. data/test/fixtures/cookbooks/bad/recipes/default.rb +1 -0
  32. data/test/fixtures/cookbooks/mini/metadata.rb +5 -0
  33. data/test/fixtures/cookbooks/mini/recipes/default.rb +1 -0
  34. data/test/fixtures/data_bags/settings/test.json +0 -0
  35. data/test/fixtures/environments/test.rb +2 -0
  36. data/test/fixtures/roles/app.rb +2 -0
  37. data/test/fixtures/roles/app1.rb +2 -0
  38. data/test/root_dir/applications/pantry/chef/roles/app.rb +2 -0
  39. data/test/unit/chef/configure_chef_test.rb +64 -0
  40. data/test/unit/chef/list_cookbooks_test.rb +49 -0
  41. data/test/unit/chef/run_chef_solo_test.rb +29 -0
  42. data/test/unit/chef/run_test.rb +5 -0
  43. data/test/unit/chef/send_cookbooks_test.rb +44 -0
  44. data/test/unit/chef/sync_cookbooks_test.rb +40 -0
  45. data/test/unit/chef/sync_data_bags_test.rb +21 -0
  46. data/test/unit/chef/sync_environments_test.rb +21 -0
  47. data/test/unit/chef/sync_roles_test.rb +21 -0
  48. data/test/unit/chef/upload_cookbook_test.rb +132 -0
  49. data/test/unit/chef/upload_data_bag_test.rb +24 -0
  50. data/test/unit/chef/upload_environment_test.rb +11 -0
  51. data/test/unit/chef/upload_role_test.rb +11 -0
  52. data/test/unit/test_helper.rb +26 -0
  53. metadata +166 -0
@@ -0,0 +1,25 @@
1
+ require 'pantry/test/acceptance'
2
+ require 'pantry/chef'
3
+
4
+ Pantry.logger.disable!
5
+ #Pantry.config.log_level = :debug
6
+
7
+ class Minitest::Test
8
+
9
+ def setup
10
+ Pantry.config.root_dir = File.expand_path("../../root_dir", __FILE__)
11
+ clean_up_pantry_root
12
+ end
13
+
14
+ # Ensure Pantry.root is always clean for each test.
15
+ def clean_up_pantry_root
16
+ Dir["#{Pantry.root}/**/*"].each do |file|
17
+ FileUtils.rm_rf file
18
+ end
19
+ end
20
+
21
+ def fixture_path(file_path)
22
+ File.join(File.dirname(__FILE__), "..", "fixtures", file_path)
23
+ end
24
+
25
+ end
@@ -0,0 +1 @@
1
+ # Do nothing
@@ -0,0 +1,5 @@
1
+ name "mini"
2
+ description "The smallest cookbook possible"
3
+ version "1.0.0"
4
+
5
+ recipe "mini", "The basic recipe"
@@ -0,0 +1,2 @@
1
+ name "test"
2
+ description "Pantry test env"
@@ -0,0 +1,2 @@
1
+ name "app"
2
+ description "Application test role"
@@ -0,0 +1,2 @@
1
+ name "app1"
2
+ description "Application test role"
@@ -0,0 +1,2 @@
1
+ name "app"
2
+ description "Application test role"
@@ -0,0 +1,64 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::ConfigureChef do
4
+
5
+ fake_fs!
6
+
7
+ it "creates expected directory structure for chef file storage" do
8
+ command = Pantry::Chef::ConfigureChef.new
9
+ command.perform(Pantry::Message.new)
10
+
11
+ %w(cache cookbooks environments).each do |dir|
12
+ assert File.directory?(Pantry.root.join("chef", dir)),
13
+ "Did not create the chef #{dir} directory"
14
+ end
15
+ end
16
+
17
+ it "writes out chef/solo.rb pointing chef to the right locations" do
18
+ command = Pantry::Chef::ConfigureChef.new
19
+ command.perform(Pantry::Message.new)
20
+
21
+ solo_rb = Pantry.root.join("etc", "chef", "solo.rb")
22
+ assert File.exists?(solo_rb), "Did not write out a solo.rb file"
23
+
24
+ solo_contents = File.read(solo_rb)
25
+
26
+ assert_match %r|cookbook_path\s*"#{Pantry.root.join("chef", "cookbooks")}|,
27
+ solo_contents
28
+ assert_match %r|file_cache_path\s*"#{Pantry.root.join("chef", "cache")}|,
29
+ solo_contents
30
+ assert_match %r|role_path\s*"#{Pantry.root.join("chef", "roles")}|,
31
+ solo_contents
32
+ assert_match %r|environment_path\s*"#{Pantry.root.join("chef", "environments")}|,
33
+ solo_contents
34
+ assert_match %r|json_attribs\s*"#{Pantry.root.join("etc", "chef", "node.json")}"|,
35
+ solo_contents
36
+ end
37
+
38
+ it "writes out the node.json file with run list based on client roles" do
39
+ client = Pantry::Client.new(roles: %w(app db))
40
+
41
+ command = Pantry::Chef::ConfigureChef.new
42
+ command.client = client
43
+ command.perform(Pantry::Message.new)
44
+
45
+ node_json = File.read(Pantry.root.join("etc", "chef", "node.json"))
46
+
47
+ assert_match "role[app]", node_json
48
+ assert_match "role[db]", node_json
49
+ end
50
+
51
+ it "writes out the current environment of the Client if one exists" do
52
+ client = Pantry::Client.new(environment: "staging")
53
+
54
+ command = Pantry::Chef::ConfigureChef.new
55
+ command.client = client
56
+ command.perform(Pantry::Message.new)
57
+
58
+ solo_rb = Pantry.root.join("etc/chef/solo.rb")
59
+ solo_contents = File.read(solo_rb)
60
+
61
+ assert_match %|environment "staging"|, solo_contents
62
+ end
63
+
64
+ end
@@ -0,0 +1,49 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::ListCookbooks do
4
+
5
+ describe "#perform" do
6
+ fake_fs!
7
+
8
+ it "returns the list of cookbooks and latest version known" do
9
+ cookbooks = [
10
+ Pantry.root.join("chef", "cookbook-cache", "mini.tgz"),
11
+ Pantry.root.join("chef", "cookbook-cache", "ruby.tgz"),
12
+ Pantry.root.join("chef", "cookbook-cache", "pantry.tgz")
13
+ ]
14
+
15
+ cookbooks.each do|c|
16
+ FileUtils.mkdir_p(File.dirname(c))
17
+ FileUtils.touch(c)
18
+ end
19
+
20
+ Pantry.stubs(:file_checksum).returns("deadbeef")
21
+
22
+ command = Pantry::Chef::ListCookbooks.new
23
+ cookbook_list = command.perform(Pantry::Message.new)
24
+
25
+ assert_equal [
26
+ ["mini", 0, "deadbeef"],
27
+ ["pantry", 0, "deadbeef"],
28
+ ["ruby", 0, "deadbeef"]
29
+ ], cookbook_list
30
+ end
31
+ end
32
+
33
+ describe "#receive_server_response" do
34
+ mock_ui!
35
+
36
+ it "displays the list alphabetical order" do
37
+ message = Pantry::Message.new
38
+ message << ["pantry", 0, "deadbeef"]
39
+ message << ["ruby", 0, "deadbeef"]
40
+ message << ["mini", 0, "deadbeef"]
41
+
42
+ command = Pantry::Chef::ListCookbooks.new
43
+ command.receive_server_response(message)
44
+
45
+ assert_equal "mini\npantry\nruby\n", stdout
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,29 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::RunChefSolo do
4
+
5
+ it "executes the chef-solo command, returning outputs" do
6
+ config_file = Pantry.root.join(*%w(etc chef solo.rb))
7
+ Open3.expects(:capture3).with("chef-solo --config #{config_file}").
8
+ returns(["chef ran", "error", 0])
9
+
10
+ command = Pantry::Chef::RunChefSolo.new
11
+ stdout, stderr, status = command.perform(Pantry::Message.new)
12
+
13
+ assert_equal "chef ran", stdout
14
+ assert_equal "error", stderr
15
+ assert_equal 0, status
16
+ end
17
+
18
+ it "returns error message if chef-solo not found on the system" do
19
+ Open3.expects(:capture3).raises(Errno::ENOENT, "Can't find LOLZ")
20
+
21
+ command = Pantry::Chef::RunChefSolo.new
22
+ stdout, stderr, status = command.perform(Pantry::Message.new)
23
+
24
+ assert_equal "", stdout
25
+ assert_equal "No such file or directory - Can't find LOLZ", stderr
26
+ assert_equal 1, status
27
+ end
28
+
29
+ end
@@ -0,0 +1,5 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::Run do
4
+
5
+ end
@@ -0,0 +1,44 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::SendCookbooks do
4
+
5
+ fake_fs!
6
+
7
+ describe "#perform" do
8
+
9
+ it "takes the list of receivers and builds senders, passing in the proper cookbook file" do
10
+ message = Pantry::Message.new
11
+ message << ["mini", "receiver_ident", "file_uuid"]
12
+ message << ["pantry", "receiver_ident2", "file_uuid2"]
13
+
14
+ cookbooks = [
15
+ Pantry.root.join("chef", "cookbook-cache", "mini.tgz"),
16
+ Pantry.root.join("chef", "cookbook-cache", "pantry.tgz")
17
+ ]
18
+
19
+ cookbooks.each do|c|
20
+ FileUtils.mkdir_p(File.dirname(c))
21
+ FileUtils.touch(c)
22
+ end
23
+
24
+ server = mock
25
+ server.expects(:send_file).with(
26
+ Pantry.root.join("chef", "cookbook-cache", "mini.tgz"),
27
+ "receiver_ident",
28
+ "file_uuid"
29
+ )
30
+
31
+ server.expects(:send_file).with(
32
+ Pantry.root.join("chef", "cookbook-cache", "pantry.tgz"),
33
+ "receiver_ident2",
34
+ "file_uuid2"
35
+ )
36
+
37
+ command = Pantry::Chef::SendCookbooks.new
38
+ command.server = server
39
+ command.perform(message)
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,40 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::SyncCookbooks do
4
+
5
+ describe "#perform" do
6
+
7
+ it "requests to the server a list of cookbooks it should have" do
8
+ client = stub_everything
9
+ client.expects(:send_request).with do |message|
10
+ assert_equal "Chef::ListCookbooks", message.type
11
+ end.returns(mock(:value => Pantry::Message.new))
12
+
13
+ command = Pantry::Chef::SyncCookbooks.new
14
+ command.client = client
15
+ command.perform(Pantry::Message.new)
16
+ end
17
+
18
+ it "fires off receivers for each cookbook in the list and waits for downloads to finish" do
19
+ client = stub_everything
20
+ message = Pantry::Message.new
21
+ message << ["cookbook1", 0, "checksum1"]
22
+
23
+ client.stubs(:send_request).returns(stub(:value => message)).times(2)
24
+
25
+ client.expects(:receive_file).with(0, "checksum1").returns(
26
+ receive_info = Pantry::Communication::FileService::ReceivingFile.new(0, "checksum1", 1, 1)
27
+ )
28
+
29
+ receive_info.expects(:wait_for_finish)
30
+
31
+ command = Pantry::Chef::SyncCookbooks.new
32
+ command.client = client
33
+ command.perform(Pantry::Message.new)
34
+ end
35
+
36
+ it "deletes cookbooks stored locally not in the list (?)"
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,21 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::SyncDataBags do
4
+
5
+ it "reads from the server directory for chef" do
6
+ cmd = Pantry::Chef::SyncDataBags.new
7
+ cmd.client = Pantry::ClientInfo.new(application: "pantry")
8
+
9
+ dir = cmd.server_directory(Pathname.new(""))
10
+ assert_equal "applications/pantry/chef/data_bags", dir.to_s
11
+ end
12
+
13
+ it "writes to the client's local chef dir" do
14
+ cmd = Pantry::Chef::SyncDataBags.new
15
+
16
+ dir = cmd.client_directory(Pathname.new(""))
17
+ assert_equal "chef/data_bags", dir.to_s
18
+ end
19
+
20
+ end
21
+
@@ -0,0 +1,21 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::SyncEnvironments do
4
+
5
+ it "reads from the server directory for chef" do
6
+ cmd = Pantry::Chef::SyncEnvironments.new
7
+ cmd.client = Pantry::ClientInfo.new(application: "pantry")
8
+
9
+ dir = cmd.server_directory(Pathname.new(""))
10
+ assert_equal "applications/pantry/chef/environments", dir.to_s
11
+ end
12
+
13
+ it "writes to the client's local chef dir" do
14
+ cmd = Pantry::Chef::SyncEnvironments.new
15
+
16
+ dir = cmd.client_directory(Pathname.new(""))
17
+ assert_equal "chef/environments", dir.to_s
18
+ end
19
+
20
+ end
21
+
@@ -0,0 +1,21 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::SyncRoles do
4
+
5
+ it "reads from the server directory for chef" do
6
+ cmd = Pantry::Chef::SyncRoles.new
7
+ cmd.client = Pantry::ClientInfo.new(application: "pantry")
8
+
9
+ dir = cmd.server_directory(Pathname.new(""))
10
+ assert_equal "applications/pantry/chef/roles", dir.to_s
11
+ end
12
+
13
+ it "writes to the client's local chef dir" do
14
+ cmd = Pantry::Chef::SyncRoles.new
15
+
16
+ dir = cmd.client_directory(Pathname.new(""))
17
+ assert_equal "chef/roles", dir.to_s
18
+ end
19
+
20
+ end
21
+
@@ -0,0 +1,132 @@
1
+ require 'unit/test_helper'
2
+
3
+ describe Pantry::Chef::UploadCookbook do
4
+
5
+ mock_ui!
6
+
7
+ def build_command(cookbook_name)
8
+ @command ||=
9
+ Pantry::Chef::UploadCookbook.new(fixture_path("cookbooks/#{cookbook_name}"))
10
+ end
11
+
12
+ describe "#prepare_message" do
13
+
14
+ after do
15
+ File.unlink(@command.cookbook_tarball) if @command && @command.cookbook_tarball
16
+ end
17
+
18
+ it "figures out name of the requested cookbook" do
19
+ command = build_command("mini")
20
+ message = command.prepare_message({})
21
+
22
+ assert_not_nil message, "Did not return a message"
23
+ assert_equal "mini", message[:cookbook_name]
24
+ end
25
+
26
+ it "tars up the cookbook, noting the size and a checksum of the file" do
27
+ command = build_command("mini")
28
+ message = command.prepare_message({})
29
+
30
+ assert message[:cookbook_size] > 0, "Did not calculate a size of the tarball"
31
+ assert_not_nil message[:cookbook_checksum], "Did not calculate a checksum"
32
+
33
+ assert_not_nil command.cookbook_tarball, "Did not save a pointer to the tarball"
34
+ assert File.exists?(command.cookbook_tarball), "No tarball found on the file system"
35
+ end
36
+
37
+ it "errors out if no metadata file" do
38
+ assert_raises Pantry::Chef::MissingMetadata do
39
+ command = build_command("bad")
40
+ command.prepare_message({})
41
+ end
42
+ end
43
+
44
+ it "errors if it can't find the cookbook" do
45
+ assert_raises Pantry::Chef::UnknownCookbook do
46
+ command = build_command("nonexist")
47
+ command.prepare_message({})
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "#perform" do
53
+
54
+ let(:incoming_message) do
55
+ m = command.to_message
56
+ m[:cookbook_name] = "testing"
57
+ m[:cookbook_size] = 100
58
+ m[:cookbook_checksum] = "123abc"
59
+ m
60
+ end
61
+
62
+ let(:command) { build_command("mini") }
63
+
64
+ let(:receiver_info) {
65
+ stub(
66
+ :file_uuid => "abc123",
67
+ :receiver_uuid => "receiver",
68
+ :on_complete => nil
69
+ )
70
+ }
71
+
72
+ it "ensures a place exists for the uploaded cookbook to go" do
73
+ command.server_or_client = stub(:receive_file => receiver_info)
74
+ response = command.perform(incoming_message)
75
+
76
+ assert File.directory?(Pantry.root.join("chef", "cookbooks")),
77
+ "Did not create directory for the testing cookbook"
78
+ end
79
+
80
+ it "responds successfully and fires off a file upload receiver" do
81
+ server_mock = mock
82
+ server_mock.expects(:receive_file).with(100, "123abc").returns(receiver_info)
83
+
84
+ command.server_or_client = server_mock
85
+
86
+ response = command.perform(incoming_message)
87
+
88
+ assert_equal [true, "receiver", "abc123"], response
89
+ end
90
+
91
+ end
92
+
93
+ describe "#receive_server_response" do
94
+
95
+ let(:command) { build_command("mini") }
96
+
97
+ it "triggers a file upload actor with the cookbook tarball and message UUID" do
98
+ client = mock
99
+ client.expects(:send_file).with do |file, receiver_uuid|
100
+ assert File.exists?(file), "Did not find the file"
101
+ assert_equal "abc123", receiver_uuid
102
+ end.returns(mock(:wait_for_finish))
103
+
104
+ command.server_or_client = client
105
+ command.prepare_message({})
106
+
107
+ response_message = Pantry::Message.new
108
+ response_message.body << "true"
109
+ response_message.body << "abc123"
110
+
111
+ command.receive_server_response(response_message)
112
+ end
113
+
114
+ it "fails out with a message and cleans up if the server response with an error" do
115
+ client = mock
116
+ client.expects(:send_file).never
117
+
118
+ command.server_or_client = client
119
+ command.prepare_message({})
120
+
121
+ response_message = Pantry::Message.new
122
+ response_message << "false"
123
+ response_message << "Unable to Upload Reason"
124
+
125
+ command.receive_server_response(response_message)
126
+
127
+ assert_match /ERROR: Unable to Upload Reason/, stdout
128
+ end
129
+
130
+ end
131
+
132
+ end