pantry-chef 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.travis.yml +16 -0
- data/Gemfile +15 -0
- data/LICENSE +20 -0
- data/README.md +49 -0
- data/Rakefile +18 -0
- data/lib/pantry/chef.rb +47 -0
- data/lib/pantry/chef/configure_chef.rb +59 -0
- data/lib/pantry/chef/list_cookbooks.rb +31 -0
- data/lib/pantry/chef/run.rb +30 -0
- data/lib/pantry/chef/run_chef_solo.rb +21 -0
- data/lib/pantry/chef/send_cookbooks.rb +23 -0
- data/lib/pantry/chef/sync_cookbooks.rb +84 -0
- data/lib/pantry/chef/sync_data_bags.rb +19 -0
- data/lib/pantry/chef/sync_environments.rb +19 -0
- data/lib/pantry/chef/sync_roles.rb +19 -0
- data/lib/pantry/chef/upload_cookbook.rb +110 -0
- data/lib/pantry/chef/upload_data_bag.rb +37 -0
- data/lib/pantry/chef/upload_environment.rb +28 -0
- data/lib/pantry/chef/upload_role.rb +28 -0
- data/lib/pantry/chef/version.rb +5 -0
- data/lib/pantry/init.rb +1 -0
- data/pantry-chef.gemspec +27 -0
- data/test/acceptance/chef/run_test.rb +69 -0
- data/test/acceptance/chef/upload_cookbook_test.rb +26 -0
- data/test/acceptance/chef/upload_data_bag_test.rb +36 -0
- data/test/acceptance/chef/upload_environment_test.rb +22 -0
- data/test/acceptance/chef/upload_role_test.rb +21 -0
- data/test/acceptance/test_helper.rb +25 -0
- data/test/fixtures/cookbooks/bad/recipes/default.rb +1 -0
- data/test/fixtures/cookbooks/mini/metadata.rb +5 -0
- data/test/fixtures/cookbooks/mini/recipes/default.rb +1 -0
- data/test/fixtures/data_bags/settings/test.json +0 -0
- data/test/fixtures/environments/test.rb +2 -0
- data/test/fixtures/roles/app.rb +2 -0
- data/test/fixtures/roles/app1.rb +2 -0
- data/test/root_dir/applications/pantry/chef/roles/app.rb +2 -0
- data/test/unit/chef/configure_chef_test.rb +64 -0
- data/test/unit/chef/list_cookbooks_test.rb +49 -0
- data/test/unit/chef/run_chef_solo_test.rb +29 -0
- data/test/unit/chef/run_test.rb +5 -0
- data/test/unit/chef/send_cookbooks_test.rb +44 -0
- data/test/unit/chef/sync_cookbooks_test.rb +40 -0
- data/test/unit/chef/sync_data_bags_test.rb +21 -0
- data/test/unit/chef/sync_environments_test.rb +21 -0
- data/test/unit/chef/sync_roles_test.rb +21 -0
- data/test/unit/chef/upload_cookbook_test.rb +132 -0
- data/test/unit/chef/upload_data_bag_test.rb +24 -0
- data/test/unit/chef/upload_environment_test.rb +11 -0
- data/test/unit/chef/upload_role_test.rb +11 -0
- data/test/unit/test_helper.rb +26 -0
- metadata +166 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 940b6c168265e478641aa40d456c2f70ce2e632e
|
4
|
+
data.tar.gz: 8c88964eadedea49879ba9ba17a2865b76c7bb53
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b57aa263239fcdc89450645200e497f9baa5e750b5224eeeef1a397d3a13cb648ffbc8808f13c41569f62905dacc87195debde5d76fda8276b5d25685aa933f3
|
7
|
+
data.tar.gz: 1fc61ebd37613a5531bcac0b56456776d4d2891cd94604b21b3e4ab6746b3ec799ee5f8c6aaf5057a43feaec023eeaa4081f851c455288dcff32ba806edd6371
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
before_install:
|
2
|
+
- travis_retry sudo apt-add-repository ppa:bpaquet/zeromq4-precise -y
|
3
|
+
- travis_retry sudo apt-get update
|
4
|
+
- travis_retry sudo apt-get install libzmq-dev -y
|
5
|
+
language: ruby
|
6
|
+
rvm:
|
7
|
+
- 2.0.0
|
8
|
+
- 2.1.0
|
9
|
+
- ruby-head
|
10
|
+
cache:
|
11
|
+
- bundler
|
12
|
+
- apt
|
13
|
+
|
14
|
+
matrix:
|
15
|
+
allow_failures:
|
16
|
+
- rvm: ruby-head
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2014 Collective Idea
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Pantry Chef
|
2
|
+
|
3
|
+
[](https://travis-ci.org/pantry/pantry-chef) [](https://codeclimate.com/github/pantry/pantry-chef)
|
4
|
+
|
5
|
+
Pantry Chef is a plugin for [Pantry](pantryops.org) to host and serve up Chef data (cookbooks, environments, roles, and data bags). Chef is run on Clients using chef-solo.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install the plugin on all nodes in the Pantry network:
|
10
|
+
|
11
|
+
gem install pantry-chef
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Once installed, using Pantry Chef is simple. You'll need to upload each of your cookbooks to the server.
|
16
|
+
|
17
|
+
pantry chef:cookbook:upload COOKBOOK_DIR
|
18
|
+
|
19
|
+
For application specific files (environments, roles, and data bags) you need to specify an application for uploading
|
20
|
+
|
21
|
+
pantry -a [application] chef:environment:upload ENVIRONMENT_FILE
|
22
|
+
...
|
23
|
+
|
24
|
+
Once all files are uploaded, trigger a Chef run on all clients:
|
25
|
+
|
26
|
+
pantry chef:run
|
27
|
+
|
28
|
+
More details can be found at http://pantryops.org/chef
|
29
|
+
|
30
|
+
## Documentation
|
31
|
+
|
32
|
+
The Documentation for Pantry is available at http://pantryops.org/chef and the RDoc is served up at [rdoc.info/pantry-chef](http://rubydoc.info/github/pantry/pantry-chef/master/frames).
|
33
|
+
|
34
|
+
## Project Details
|
35
|
+
|
36
|
+
* Built and Maintained by [Collective Idea](http://collectiveidea.com)
|
37
|
+
* Hosted on Github [pantry/pantry-chef](https://github.com/pantry/pantry-chef)
|
38
|
+
* File bug reports on the [Issue tracker](https://github.com/pantry/pantry-chef/issues)
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
* Fork this repository on Github
|
43
|
+
* Make your changes and send us a Pull Request
|
44
|
+
* All Pull Requests must contain tests
|
45
|
+
* Pull Request tests must pass before being accepted
|
46
|
+
|
47
|
+
## License
|
48
|
+
|
49
|
+
Pantry Chef is distributed under the MIT License. See LICENSE for more details.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
task :default => "test:all"
|
4
|
+
|
5
|
+
namespace :test do
|
6
|
+
desc "Run all test suites"
|
7
|
+
task :all => [:unit, :acceptance]
|
8
|
+
|
9
|
+
Rake::TestTask.new(:unit) do |t|
|
10
|
+
t.libs << "test" << "lib"
|
11
|
+
t.pattern = "test/unit/**/*_test.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
Rake::TestTask.new(:acceptance) do |t|
|
15
|
+
t.libs << "test" << "lib"
|
16
|
+
t.pattern = "test/acceptance/**/*_test.rb"
|
17
|
+
end
|
18
|
+
end
|
data/lib/pantry/chef.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'pantry/chef/version'
|
2
|
+
|
3
|
+
require 'pantry/chef/upload_cookbook'
|
4
|
+
require 'pantry/chef/list_cookbooks'
|
5
|
+
require 'pantry/chef/sync_cookbooks'
|
6
|
+
require 'pantry/chef/send_cookbooks'
|
7
|
+
|
8
|
+
require 'pantry/chef/upload_role'
|
9
|
+
require 'pantry/chef/sync_roles'
|
10
|
+
|
11
|
+
require 'pantry/chef/upload_environment'
|
12
|
+
require 'pantry/chef/sync_environments'
|
13
|
+
|
14
|
+
require 'pantry/chef/upload_data_bag'
|
15
|
+
require 'pantry/chef/sync_data_bags'
|
16
|
+
|
17
|
+
require 'pantry/chef/configure_chef'
|
18
|
+
require 'pantry/chef/run_chef_solo'
|
19
|
+
require 'pantry/chef/run'
|
20
|
+
|
21
|
+
module Pantry
|
22
|
+
module Chef
|
23
|
+
|
24
|
+
class UnknownCookbook < Exception; end
|
25
|
+
|
26
|
+
class MissingMetadata < Exception; end
|
27
|
+
|
28
|
+
class UploadError < Exception; end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Pantry.add_server_command(Pantry::Chef::UploadCookbook)
|
34
|
+
Pantry.add_server_command(Pantry::Chef::ListCookbooks)
|
35
|
+
Pantry.add_server_command(Pantry::Chef::SendCookbooks)
|
36
|
+
|
37
|
+
Pantry.add_server_command(Pantry::Chef::UploadRole)
|
38
|
+
Pantry.add_server_command(Pantry::Chef::UploadEnvironment)
|
39
|
+
Pantry.add_server_command(Pantry::Chef::UploadDataBag)
|
40
|
+
|
41
|
+
Pantry.add_client_command(Pantry::Chef::Run)
|
42
|
+
Pantry.add_client_command(Pantry::Chef::ConfigureChef)
|
43
|
+
Pantry.add_client_command(Pantry::Chef::SyncCookbooks)
|
44
|
+
Pantry.add_client_command(Pantry::Chef::SyncRoles)
|
45
|
+
Pantry.add_client_command(Pantry::Chef::SyncEnvironments)
|
46
|
+
Pantry.add_client_command(Pantry::Chef::SyncDataBags)
|
47
|
+
Pantry.add_client_command(Pantry::Chef::RunChefSolo)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Pantry
|
2
|
+
module Chef
|
3
|
+
|
4
|
+
class ConfigureChef < Pantry::Command
|
5
|
+
|
6
|
+
def perform(message)
|
7
|
+
@base_chef_dir = Pantry.root.join("chef")
|
8
|
+
@etc_dir = Pantry.root.join("etc", "chef")
|
9
|
+
create_required_directories
|
10
|
+
write_solo_rb
|
11
|
+
write_node_json
|
12
|
+
# TODO: Error handling response message?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def create_required_directories
|
19
|
+
FileUtils.mkdir_p(@base_chef_dir.join("cache"))
|
20
|
+
FileUtils.mkdir_p(@base_chef_dir.join("cookbooks"))
|
21
|
+
FileUtils.mkdir_p(@base_chef_dir.join("environments"))
|
22
|
+
FileUtils.mkdir_p(@etc_dir)
|
23
|
+
end
|
24
|
+
|
25
|
+
# NOTE: Writes out the file every time this command is run.
|
26
|
+
def write_solo_rb
|
27
|
+
contents = ["# This file generated by Pantry", ""]
|
28
|
+
|
29
|
+
if client && client.environment
|
30
|
+
contents << %|environment "#{client.environment}"|
|
31
|
+
end
|
32
|
+
|
33
|
+
contents << %|file_cache_path "#{@base_chef_dir.join("cache")}"|
|
34
|
+
contents << %|cookbook_path "#{@base_chef_dir.join("cookbooks")}"|
|
35
|
+
contents << %|environment_path "#{@base_chef_dir.join("environments")}"|
|
36
|
+
contents << %|role_path "#{@base_chef_dir.join("roles")}"|
|
37
|
+
contents << %|json_attribs "#{@etc_dir.join("node.json")}"|
|
38
|
+
|
39
|
+
File.open(@etc_dir.join("solo.rb"), "w+") do |file|
|
40
|
+
file.write(contents.join("\n") + "\n")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_node_json
|
45
|
+
return unless client
|
46
|
+
|
47
|
+
node_json = @etc_dir.join("node.json")
|
48
|
+
|
49
|
+
File.open(node_json, "w+") do |file|
|
50
|
+
file.write({
|
51
|
+
"run_list" => client.roles.map {|r| "role[#{r}]" }
|
52
|
+
}.to_json)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Pantry
|
2
|
+
module Chef
|
3
|
+
|
4
|
+
# List all cookbooks known by the Server.
|
5
|
+
# This message includes the size and checksum of the cookbooks's tarball as it's used
|
6
|
+
# when sending cookbooks down to a Client.
|
7
|
+
class ListCookbooks < Pantry::Command
|
8
|
+
|
9
|
+
command "chef:cookbook:list" do
|
10
|
+
description "List all known cookbooks on the server."
|
11
|
+
group "Chef"
|
12
|
+
end
|
13
|
+
|
14
|
+
def perform(message)
|
15
|
+
Dir[Pantry.root.join("chef", "cookbook-cache", "*")].map do |cookbook_path|
|
16
|
+
[
|
17
|
+
File.basename(cookbook_path, ".tgz"),
|
18
|
+
File.size(cookbook_path),
|
19
|
+
Pantry.file_checksum(cookbook_path)
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def receive_server_response(message)
|
25
|
+
Pantry.ui.list(message.body.map(&:first).sort)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Pantry
|
2
|
+
module Chef
|
3
|
+
|
4
|
+
class Run < Pantry::MultiCommand
|
5
|
+
|
6
|
+
command "chef:run" do
|
7
|
+
description "Run Chef on Clients"
|
8
|
+
group "Chef"
|
9
|
+
end
|
10
|
+
|
11
|
+
performs [
|
12
|
+
ConfigureChef,
|
13
|
+
SyncCookbooks,
|
14
|
+
SyncRoles,
|
15
|
+
SyncEnvironments,
|
16
|
+
SyncDataBags,
|
17
|
+
RunChefSolo
|
18
|
+
]
|
19
|
+
|
20
|
+
def receive_client_response(response)
|
21
|
+
Pantry.ui.say("Chef on #{response.from} finished")
|
22
|
+
Pantry.ui.say(response.body[5][0])
|
23
|
+
Pantry.ui.say(response.body[5][1])
|
24
|
+
Pantry.ui.say("")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pantry
|
2
|
+
module Chef
|
3
|
+
|
4
|
+
# Execute ChefSolo on the current box, returning STDOUT, STDERR, and status code.
|
5
|
+
class RunChefSolo < Pantry::Command
|
6
|
+
|
7
|
+
def perform(message)
|
8
|
+
begin
|
9
|
+
solo_rb = Pantry.root.join("etc", "chef", "solo.rb")
|
10
|
+
stdout, stderr, status = Open3.capture3("chef-solo --config #{solo_rb}")
|
11
|
+
[stdout, stderr, status.to_i]
|
12
|
+
rescue Exception => e
|
13
|
+
# Could not find the chef-solo binary
|
14
|
+
["", e.message, 1]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pantry
|
2
|
+
module Chef
|
3
|
+
|
4
|
+
# Given a list of cookbooks and the Receivers waiting for them,
|
5
|
+
# set up some senders to start sending the appropriate Cookbook files along.
|
6
|
+
class SendCookbooks < Pantry::Command
|
7
|
+
|
8
|
+
def perform(message)
|
9
|
+
message.body.each do |(name, receiver_uuid, file_uuid)|
|
10
|
+
server.send_file(
|
11
|
+
Pantry.root.join("chef", "cookbook-cache", "#{name}.tgz"),
|
12
|
+
receiver_uuid,
|
13
|
+
file_uuid
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Pantry
|
2
|
+
module Chef
|
3
|
+
|
4
|
+
# Client syncs up it's local list of Chef Cookbooks with what the Server
|
5
|
+
# says the Client should have.
|
6
|
+
class SyncCookbooks < Pantry::Command
|
7
|
+
|
8
|
+
def perform(message)
|
9
|
+
cookbooks_to_download = ask_server_for_cookbook_list
|
10
|
+
Pantry.logger.debug("[#{client.identity}] Downloading cookbooks #{cookbooks_to_download}")
|
11
|
+
|
12
|
+
recievers = build_cookbook_receivers(cookbooks_to_download)
|
13
|
+
send_receiver_information_to_server(recievers)
|
14
|
+
wait_for_receivers_to_finish(recievers)
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
class FileAndReceiverInfo
|
21
|
+
include Forwardable
|
22
|
+
|
23
|
+
attr_reader :name
|
24
|
+
|
25
|
+
def initialize(name, receiver_info)
|
26
|
+
@name = name
|
27
|
+
@receiver_info = receiver_info
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(*args, &block)
|
31
|
+
@receiver_info.send(*args, &block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def ask_server_for_cookbook_list
|
36
|
+
send_request!(Pantry::Chef::ListCookbooks.new.to_message).body
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_cookbook_receivers(cookbook_list)
|
40
|
+
cookbook_list.map do |(name, size, checksum)|
|
41
|
+
receive_info = FileAndReceiverInfo.new(name, client.receive_file(size, checksum))
|
42
|
+
receive_info.on_complete(&unpack_received_file(receive_info))
|
43
|
+
receive_info
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def unpack_received_file(receiver_info)
|
48
|
+
lambda do
|
49
|
+
stdout, stderr = Open3.capture2e(
|
50
|
+
"tar",
|
51
|
+
"-xzC", Pantry.root.join("chef", "cookbooks").to_s,
|
52
|
+
"-f", receiver_info.uploaded_path
|
53
|
+
)
|
54
|
+
|
55
|
+
Pantry.logger.debug("[#{client.identity}] Unpack cookbook #{stdout.inspect}, #{stderr.inspect}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def send_receiver_information_to_server(receivers)
|
60
|
+
download_message = Pantry::Chef::SendCookbooks.new.to_message
|
61
|
+
|
62
|
+
receivers.each do |receiver_info|
|
63
|
+
download_message << [
|
64
|
+
receiver_info.name,
|
65
|
+
receiver_info.receiver_uuid,
|
66
|
+
receiver_info.file_uuid
|
67
|
+
]
|
68
|
+
end
|
69
|
+
|
70
|
+
if receivers.any?
|
71
|
+
send_request(download_message)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def wait_for_receivers_to_finish(receivers)
|
76
|
+
receivers.each do |receive_info|
|
77
|
+
receive_info.wait_for_finish
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Pantry
|
2
|
+
module Chef
|
3
|
+
|
4
|
+
# Client syncs up it's local list of data bags with what the Server
|
5
|
+
# says the Client should have.
|
6
|
+
class SyncDataBags < Pantry::Commands::SyncDirectory
|
7
|
+
|
8
|
+
def server_directory(local_root)
|
9
|
+
local_root.join("applications", client.application, "chef", "data_bags")
|
10
|
+
end
|
11
|
+
|
12
|
+
def client_directory(local_root)
|
13
|
+
local_root.join("chef", "data_bags")
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|