fry-cook 0.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/README.md +135 -0
- data/bin/fry-cook +69 -0
- data/lib/fry-cook.rb +3 -0
- data/lib/fry_cook/.version.rb.swp +0 -0
- data/lib/fry_cook/server.rb +24 -0
- data/lib/fry_cook/vagrant_plugin.rb +32 -0
- data/lib/fry_cook/vagrant_plugin/config.rb +38 -0
- data/lib/fry_cook/vagrant_plugin/hooks.rb +99 -0
- data/lib/fry_cook/version.rb +3 -0
- data/lib/fry_cook/work_tree.rb +184 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6bb59c77a0a41152f10c174fafcd5af5b0e2ecc2
|
4
|
+
data.tar.gz: 999b3e34abaaa77b593da933634dae1b28ac6008
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 63627e5591cda4bb4646b2267fa979378bd41600ac2d4bc90bb7123b12495dbdc1732fa2ee70b4605ddaa0e466c6f549f26265e89fa4b24aabf9dbb14c6c5aff
|
7
|
+
data.tar.gz: ef31001c347c70f867827d59b6b62e24d4d5cbcbecc82c30403a55acfa96968c8b6c0459ef65ddee302d7920be2e4025005059a3d1bb43cb94b3246af8a6262e
|
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2013, Graham Batty
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
The views and conclusions contained in the software and documentation are those
|
25
|
+
of the authors and should not be interpreted as representing official policies,
|
26
|
+
either expressed or implied, of the Project.
|
data/README.md
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# Fry Cook
|
2
|
+
|
3
|
+
*Not quite a chef yet, the fry cook knows only one menu.*
|
4
|
+
|
5
|
+
Fry Cook is a chef server that is designed to be used with a
|
6
|
+
git repository (or working directory) that is to be treated as
|
7
|
+
a definitive source of truth. It is based on chef zero with
|
8
|
+
the Chef local filesystem data source, but has some modifications
|
9
|
+
on top of that.
|
10
|
+
|
11
|
+
## Standalone Usage
|
12
|
+
|
13
|
+
Fry Cook can be used as a standalone server just like a normal
|
14
|
+
chef server. All the caveats of using this as a chef server apply
|
15
|
+
as using [https://github.com/opscode/chef-zero](Chef-Zero). It
|
16
|
+
doesn't authenticate anything. This is because it uses chef-zero
|
17
|
+
to do most of the work.
|
18
|
+
|
19
|
+
However, it can be useful in ways that chef-zero is not. Namely,
|
20
|
+
it can seed your cookbooks from a git repository and even build
|
21
|
+
those cookbooks from a Berksfile. It will also convert all .rb files
|
22
|
+
to .json files as expected by the chef server. This is all a much
|
23
|
+
faster option than setting up a chef server and uploading everything
|
24
|
+
to it.
|
25
|
+
|
26
|
+
If you run fry-cook --help you will see this:
|
27
|
+
|
28
|
+
```bash
|
29
|
+
Usage: fry-cook [ARGS]
|
30
|
+
-H, --host HOST Host to bind to (default: 127.0.0.1)
|
31
|
+
-p, --port PORT Port to listen on (default: 8889)
|
32
|
+
--socket PATH Unix socket path to listen on
|
33
|
+
-d, --daemon Run as a daemon process
|
34
|
+
--path PATH A working copy of the chef-repo to build from (default: .)
|
35
|
+
--remote GIT_REMOTE A git remote to build from
|
36
|
+
--track GIT_REF The branch (or other ref) to track in the git remote (default: master)
|
37
|
+
--storage-path PATH Where to store the files the server works from (default: {working_path}/.fry-cook
|
38
|
+
-l, --log-level LEVEL Set the output log level
|
39
|
+
-h, --help Show this message
|
40
|
+
--version Show version
|
41
|
+
```
|
42
|
+
|
43
|
+
The arguments that differ from chef-zero are the path, remote,
|
44
|
+
track, and storage-path options. Fry-cook effectively has two modes,
|
45
|
+
depending on where you want to build your working chef server from:
|
46
|
+
|
47
|
+
### From a Local Path
|
48
|
+
|
49
|
+
You can build from a local path, like a working copy of a git repository. This
|
50
|
+
is great for development or using as a vagrant plugin (below). To use this mode you
|
51
|
+
can simply pass nothing special and it will assume the current working directory
|
52
|
+
is the local path you want to work from. To explicitly specify a path, you can
|
53
|
+
pass the --path option.
|
54
|
+
|
55
|
+
You should not pass the remote or track arguments for this mode. They put it
|
56
|
+
into the git mode, described in the next section.
|
57
|
+
|
58
|
+
Examples:
|
59
|
+
|
60
|
+
```bash
|
61
|
+
fry-cook -d # The current working directory should be a chef repo.
|
62
|
+
```
|
63
|
+
|
64
|
+
```bash
|
65
|
+
fry-cook -d --path /var/lib/chef # Build from /var/lib/chef.
|
66
|
+
```
|
67
|
+
|
68
|
+
### From a Git Repository or Remote
|
69
|
+
|
70
|
+
If you want to build your chef server configuration from a remote git repository,
|
71
|
+
say on github or some other central repository, you can use the remote and track
|
72
|
+
arguments. Remote is a git remote, such as ```git@github.com:stormbrew/fry-cook.git```.
|
73
|
+
Track is the reference within the repository, which could be a branch or tag. It
|
74
|
+
defaults to the master branch.
|
75
|
+
|
76
|
+
Examples:
|
77
|
+
|
78
|
+
```bash
|
79
|
+
fry-cook -d --remote git@github.com:stormbrew/mything.git # Master branch of mything on github.
|
80
|
+
```
|
81
|
+
|
82
|
+
```bash
|
83
|
+
fry-cook -d --remote git@github.com:stormbew/mything.git --track production # Production branch of mything on github.
|
84
|
+
```
|
85
|
+
|
86
|
+
### Storage Path
|
87
|
+
|
88
|
+
The storage path is where fry-cook builds into. Every time it builds from
|
89
|
+
the source it builds into a fresh directory. It also keeps the uploaded node
|
90
|
+
json files in here in a way that persists across rebuilds.
|
91
|
+
|
92
|
+
This setup is designed to allow rebuilding from the repository on a live
|
93
|
+
server without turning it off. This feature will be added later.
|
94
|
+
|
95
|
+
Most of the time you'll want to leave this as the default, which will
|
96
|
+
put it in a .fry-cook directory in the current working directory.
|
97
|
+
|
98
|
+
## Using With Vagrant
|
99
|
+
|
100
|
+
If you install Fry Cook as a vagrant plugin you can use it in much the same
|
101
|
+
way as the vagrant-chef-zero plugin. You don't need to install a separate
|
102
|
+
plugin to do this, just ```vagrant plugin install fry-cook```. From there
|
103
|
+
you can add it to your Vagrantfile as follows:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
Vagrant.configure("2") do |config|
|
107
|
+
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
|
108
|
+
config.omnibus.chef_version = "11.8.0"
|
109
|
+
|
110
|
+
## For a local repository
|
111
|
+
config.fry_cook.repo_path = "."
|
112
|
+
|
113
|
+
## For a remote repository
|
114
|
+
# config.fry_cook.repo_git_remote = "git@github.com:stormbrew/stuff.git"
|
115
|
+
# config.fry_cook.repo_git_ref = "master" # optional
|
116
|
+
|
117
|
+
## If you have multiple vms in your vagrantfile and you
|
118
|
+
## want them to use a different chef server, you can set
|
119
|
+
## them up to use different 'prefixes' and different server
|
120
|
+
## ports (default is 18999) to keep them separate:
|
121
|
+
# config.fry_cook.prefix = "config1"
|
122
|
+
# config.fry_cook.server_port = 9432
|
123
|
+
|
124
|
+
config.vm.provision :chef_client do |chef_client|
|
125
|
+
chef_client.add_recipe "apt"
|
126
|
+
chef_client.add_recipe "nginx"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
## Future Work
|
132
|
+
|
133
|
+
This really needs more testing infrastructure (or any at all). It also needs
|
134
|
+
a command to rebuild the repo without restarting the server, which is not
|
135
|
+
terribly difficult.
|
data/bin/fry-cook
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "fry_cook/version"
|
4
|
+
require "chef_zero/version"
|
5
|
+
require "fry_cook/server"
|
6
|
+
require "optparse"
|
7
|
+
|
8
|
+
options = {}
|
9
|
+
fry_options = {}
|
10
|
+
|
11
|
+
OptionParser.new do |opts|
|
12
|
+
opts.banner = "Usage: fry-cook [ARGS]"
|
13
|
+
|
14
|
+
opts.on("-H", "--host HOST", "Host to bind to (default: 127.0.0.1)") do |value|
|
15
|
+
options[:host] = value
|
16
|
+
end
|
17
|
+
opts.on("-p", "--port PORT", Integer, "Port to listen on (default: 8889)") do |value|
|
18
|
+
options[:port] = value
|
19
|
+
end
|
20
|
+
opts.on("--socket PATH", String, "Unix socket path to listen on") do |value|
|
21
|
+
options[:socket] = value
|
22
|
+
end
|
23
|
+
opts.on("-d", "--daemon", "Run as a daemon process") do |value|
|
24
|
+
options[:daemon] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("--path PATH", String, "A working copy of the chef-repo to build from (default: .)") do |value|
|
28
|
+
fry_options[:working_path] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("--remote GIT_REMOTE", String, "A git remote to build from") do |value|
|
32
|
+
fry_options[:git_repo_remote] = value
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("--track GIT_REF", String, "The branch (or other ref) to track in the git remote (default: master)") do |value|
|
36
|
+
fry_options[:git_ref] = value
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("--storage-path PATH", String, "Where to store the files the server works from (default: {working_path}/.fry-cook") do |value|
|
40
|
+
fry_options[:storage_path] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-l", "--log-level LEVEL", "Set the output log level") do |value|
|
44
|
+
options[:log_level] = value
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
48
|
+
puts opts
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on_tail("--version", "Show version") do
|
53
|
+
puts "fry-cook-#{FryCook::VERSION}, chef-zero-#{ChefZero::VERSION}"
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
end.parse!
|
57
|
+
|
58
|
+
server = FryCook::Server.new(options, fry_options)
|
59
|
+
|
60
|
+
if options[:daemon]
|
61
|
+
unless Process.respond_to?('daemon')
|
62
|
+
abort 'Process.deamon requires Ruby >= 1.9'
|
63
|
+
else
|
64
|
+
Process.daemon(true)
|
65
|
+
server.start(:publish => true)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
server.start(:publish => true)
|
69
|
+
end
|
data/lib/fry-cook.rb
ADDED
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'chef_zero/server'
|
2
|
+
require 'fry_cook/work_tree'
|
3
|
+
|
4
|
+
module FryCook
|
5
|
+
class Server < ChefZero::Server
|
6
|
+
def initialize(chef_options, fry_options)
|
7
|
+
@work_tree = WorkTree.new(fry_options)
|
8
|
+
@work_tree.build
|
9
|
+
|
10
|
+
Chef::Config.node_path = @work_tree.node_path
|
11
|
+
Chef::Config.cookbook_path = @work_tree.cookbook_path
|
12
|
+
Chef::Config.role_path = @work_tree.role_path
|
13
|
+
Chef::Config.data_bag_path = @work_tree.data_bag_path
|
14
|
+
Chef::Config.environment_path = @work_tree.environment_path
|
15
|
+
|
16
|
+
data_store = Chef::ChefFS::ChefFSDataStore.new(
|
17
|
+
Chef::ChefFS::Config.new(Chef::Config).local_fs
|
18
|
+
)
|
19
|
+
chef_options[:data_store] = data_store
|
20
|
+
|
21
|
+
super(chef_options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module FryCook
|
2
|
+
module VagrantPlugin
|
3
|
+
class Plugin < ::Vagrant.plugin("2")
|
4
|
+
name "fry-cook"
|
5
|
+
description <<-DESC
|
6
|
+
Auto-configurator for fry cook for the chef_client provisioner.
|
7
|
+
DESC
|
8
|
+
|
9
|
+
config(:fry_cook) do
|
10
|
+
require File.expand_path("../vagrant_plugin/config", __FILE__)
|
11
|
+
Config
|
12
|
+
end
|
13
|
+
|
14
|
+
action_hook(:fry_cook_reconfig) do |hook|
|
15
|
+
chain = Vagrant::Action::Builder.new.tap do |b|
|
16
|
+
require File.expand_path("../vagrant_plugin/hooks", __FILE__)
|
17
|
+
b.use Hooks::ConfigureServerUrl
|
18
|
+
end
|
19
|
+
hook.before(::Vagrant::Action::Builtin::ConfigValidate, chain)
|
20
|
+
end
|
21
|
+
%w{up reload provision}.each do |action|
|
22
|
+
action_hook(:"fry_cook_#{action}", :"machine_action_#{action}") do |hook|
|
23
|
+
chain = Vagrant::Action::Builder.new.tap do |b|
|
24
|
+
require File.expand_path("../vagrant_plugin/hooks", __FILE__)
|
25
|
+
b.use Hooks::StartServer
|
26
|
+
end
|
27
|
+
hook.before(::Vagrant::Action::Builtin::Provision, chain)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module FryCook
|
2
|
+
module VagrantPlugin
|
3
|
+
class Config < Vagrant.plugin("2", :config)
|
4
|
+
def self.config_attr(name, default = nil, &block)
|
5
|
+
@config_attrs ||= {}
|
6
|
+
@config_attrs[name] = block || default
|
7
|
+
attr_accessor name
|
8
|
+
end
|
9
|
+
def self.config_attrs
|
10
|
+
@config_attrs || {}
|
11
|
+
end
|
12
|
+
|
13
|
+
config_attr :repo_path
|
14
|
+
config_attr :repo_git_remote
|
15
|
+
config_attr :repo_git_track, "master"
|
16
|
+
config_attr :prefix, "default"
|
17
|
+
config_attr :server_port, 18998
|
18
|
+
|
19
|
+
def initialize()
|
20
|
+
self.class.config_attrs.each do |config_attr, default|
|
21
|
+
instance_variable_set(:"@#{config_attr}", UNSET_VALUE)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def finalize!
|
26
|
+
self.class.config_attrs.each do |config_attr, default|
|
27
|
+
if instance_variable_get(:"@#{config_attr}") == UNSET_VALUE
|
28
|
+
if default.respond_to? :call
|
29
|
+
default = default.call
|
30
|
+
end
|
31
|
+
instance_variable_set(:"@#{config_attr}", default)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
{}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'openssl'
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'fry_cook/server'
|
5
|
+
|
6
|
+
module FryCook::VagrantPlugin::Hooks
|
7
|
+
class Base
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@env = env
|
11
|
+
end
|
12
|
+
|
13
|
+
def config
|
14
|
+
@env[:machine].config.fry_cook
|
15
|
+
end
|
16
|
+
|
17
|
+
def client_config
|
18
|
+
@env[:machine].config.vm.provisioners.select {|prov| prov.name == :chef_client }
|
19
|
+
end
|
20
|
+
|
21
|
+
def active?
|
22
|
+
client_config.any? && config.repo_path || config.repo_git_remote
|
23
|
+
end
|
24
|
+
|
25
|
+
def host_ip_address
|
26
|
+
# This gets the first ip address in a private range. With virtualbox,
|
27
|
+
# at least, things seem to be routed so that the vm can connect to this
|
28
|
+
# IP even if it has nothing to do with vagrant or virtualbox. This may not
|
29
|
+
# be an entirely safe assumption, but vagrant doesn't provide any kind of
|
30
|
+
# better way to obtain a canonical reachable address as far as I can tell.
|
31
|
+
Socket.ip_address_list.detect{|intf| intf.ipv4_private?}.ip_address
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(env)
|
35
|
+
@env = env
|
36
|
+
if active?
|
37
|
+
do_action(env)
|
38
|
+
end
|
39
|
+
@app.call(env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class ConfigureServerUrl < Base
|
44
|
+
def get_fake_key_path
|
45
|
+
fake_directory = File.join(Dir.tmpdir, "fake_key")
|
46
|
+
fake_key_path = File.join(fake_directory, "fake.pem")
|
47
|
+
|
48
|
+
if !File.exists?(fake_key_path)
|
49
|
+
fake_key = OpenSSL::PKey::RSA.new(2048)
|
50
|
+
Dir.mkdir(fake_directory) unless File.exists?(fake_directory)
|
51
|
+
File.open(fake_key_path,"w") {|f| f.puts fake_key }
|
52
|
+
end
|
53
|
+
|
54
|
+
fake_key_path
|
55
|
+
end
|
56
|
+
|
57
|
+
def do_action(env)
|
58
|
+
client_config.each do |client|
|
59
|
+
fake_key = get_fake_key_path
|
60
|
+
|
61
|
+
if !client.config.instance_variable_get(:"@chef_server_url")
|
62
|
+
client.config.instance_variable_set(:"@chef_server_url", "http://#{host_ip_address}:#{config.server_port}/")
|
63
|
+
end
|
64
|
+
if !client.config.instance_variable_get(:@validation_key_path)
|
65
|
+
client.config.instance_variable_set(:@validation_key_path, fake_key)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class StartServer < Base
|
72
|
+
def do_action(env)
|
73
|
+
# Note: This is not thread safe, but it may not entirely
|
74
|
+
# be able to be. I don't think vagrant would run these in
|
75
|
+
# parallel at the moment at any rate.
|
76
|
+
if !defined? @@running
|
77
|
+
server_options = {
|
78
|
+
host: host_ip_address,
|
79
|
+
port: config.server_port,
|
80
|
+
daemon: false,
|
81
|
+
}
|
82
|
+
fry_options = {
|
83
|
+
storage_path: ".vagrant/fry-cook/#{config.prefix}",
|
84
|
+
}
|
85
|
+
case
|
86
|
+
when config.repo_path
|
87
|
+
fry_options[:working_path] = config.repo_path
|
88
|
+
when config.repo_git_remote
|
89
|
+
fry_options[:git_repo_remote] = config.repo_git_remote
|
90
|
+
fry_options[:git_ref] = config.repo_git_track
|
91
|
+
end
|
92
|
+
|
93
|
+
server = FryCook::Server.new(server_options, fry_options)
|
94
|
+
server.start_background
|
95
|
+
@@running = true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'chef/chef_fs/chef_fs_data_store'
|
2
|
+
require 'chef/chef_fs/config'
|
3
|
+
require 'chef/role'
|
4
|
+
require 'chef/environment'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'json'
|
7
|
+
require 'berkshelf'
|
8
|
+
|
9
|
+
module FryCook
|
10
|
+
class WorkTree
|
11
|
+
attr_reader :storage_path
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
if options[:storage_path] && File.file?("#{options[:storage_path]}/config.json")
|
15
|
+
existing_config = JSON.load(File.read("#{options[:storage_path]}/config.json"), nil, symbolize_names: true)
|
16
|
+
options = existing_config.merge(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
if options[:git_repo_remote]
|
20
|
+
@mode = :git
|
21
|
+
@git_remote = options[:git_repo_remote]
|
22
|
+
@git_ref = options[:git_ref] || 'master'
|
23
|
+
@storage_path = options[:storage_path] || raise("Must specify storage path for git mode.")
|
24
|
+
@git_repo = "#{@storage_path}/git-repo"
|
25
|
+
else
|
26
|
+
@mode = :path
|
27
|
+
@working_path = options[:working_path] || '.'
|
28
|
+
@storage_path = options[:storage_path] || "#{@working_path}/.fry-cook"
|
29
|
+
end
|
30
|
+
|
31
|
+
FileUtils.mkdir_p(@storage_path)
|
32
|
+
FileUtils.mkdir_p("#{@storage_path}/nodes")
|
33
|
+
|
34
|
+
File.write("#{@storage_path}/config.json", JSON.dump(options))
|
35
|
+
end
|
36
|
+
|
37
|
+
def node_path
|
38
|
+
"#{storage_path}/nodes"
|
39
|
+
end
|
40
|
+
def cookbook_path
|
41
|
+
"#{storage_path}/current/cookbooks"
|
42
|
+
end
|
43
|
+
def role_path
|
44
|
+
"#{storage_path}/current/roles"
|
45
|
+
end
|
46
|
+
def data_bag_path
|
47
|
+
"#{storage_path}/current/data_bags"
|
48
|
+
end
|
49
|
+
def environment_path
|
50
|
+
"#{storage_path}/current/environments"
|
51
|
+
end
|
52
|
+
|
53
|
+
def cmd(cmd)
|
54
|
+
res = IO.popen(cmd, :err=>[:child, :out]) do |p|
|
55
|
+
p.readlines.collect {|line| line.chomp }
|
56
|
+
end
|
57
|
+
if !$?.success?
|
58
|
+
raise("Command #{cmd.join(' ')} failed:\n#{res.join("\n")}")
|
59
|
+
end
|
60
|
+
res
|
61
|
+
end
|
62
|
+
def git(*cmd)
|
63
|
+
cmd(["git", "--git-dir", @git_repo, *cmd])
|
64
|
+
end
|
65
|
+
def git_in(work_path, *cmd)
|
66
|
+
FileUtils.mkdir_p(work_path)
|
67
|
+
git("--work-tree", work_path, *cmd)
|
68
|
+
end
|
69
|
+
|
70
|
+
def git_refresh
|
71
|
+
if !File.directory? @git_repo
|
72
|
+
git("clone", "--bare", @git_remote, @git_repo)
|
73
|
+
end
|
74
|
+
git("fetch", '-f', @git_remote, 'refs/heads/*:refs/heads/*')
|
75
|
+
end
|
76
|
+
|
77
|
+
def pull_source
|
78
|
+
case @mode
|
79
|
+
when :git
|
80
|
+
git_refresh
|
81
|
+
new_ref = git("rev-parse", @git_ref)
|
82
|
+
if new_ref.length == 0
|
83
|
+
raise("Didn't get a valid ref for #{@git_ref}")
|
84
|
+
end
|
85
|
+
new_version = "build-" + new_ref[0]
|
86
|
+
source_path = "#{@storage_path}/#{new_version}/chef_repo"
|
87
|
+
if !File.directory? source_path
|
88
|
+
git_in(source_path, "checkout", "-f", @git_ref)
|
89
|
+
end
|
90
|
+
when :path
|
91
|
+
new_version = "build-#{Time.now.to_i}"
|
92
|
+
source_path = @working_path
|
93
|
+
end
|
94
|
+
return new_version, source_path
|
95
|
+
end
|
96
|
+
|
97
|
+
def install_cookbooks(new_version, source_path, install_path)
|
98
|
+
case
|
99
|
+
when File.file?("#{source_path}/Berksfile")
|
100
|
+
# Note: Doesn't work properly without being in the directory of the berksfile.
|
101
|
+
Dir.chdir(source_path) do
|
102
|
+
berksfile = Berkshelf::Berksfile.from_file("Berksfile")
|
103
|
+
berksfile.vendor("#{install_path}/cookbooks")
|
104
|
+
end
|
105
|
+
when File.directory?("#{source_path}/cookbooks")
|
106
|
+
FileUtils.cp_r("#{source_path}/cookbooks", "#{install_path}/cookbooks")
|
107
|
+
else
|
108
|
+
raise("No cookbooks found.")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def install_environments(new_version, source_path, install_path)
|
113
|
+
FileUtils.mkdir_p("#{install_path}/environments")
|
114
|
+
environments = Dir.glob("#{source_path}/environments/*.json")
|
115
|
+
if !environments.empty?
|
116
|
+
FileUtils.cp(environments, "#{install_path}/environments")
|
117
|
+
end
|
118
|
+
Dir.glob("#{source_path}/environments/*.rb").each do |environment|
|
119
|
+
environment_obj = Chef::Environment.new
|
120
|
+
environment_obj.name File.basename(environment, ".rb")
|
121
|
+
environment_obj.from_file(environment)
|
122
|
+
File.write("#{install_path}/environments/#{File.basename(environment, ".rb")}.json", environment_obj.to_json)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def install_roles(new_version, source_path, install_path)
|
127
|
+
FileUtils.mkdir_p("#{install_path}/roles")
|
128
|
+
roles = Dir.glob("#{source_path}/roles/*.json")
|
129
|
+
if !roles.empty?
|
130
|
+
FileUtils.cp(roles, "#{install_path}/roles")
|
131
|
+
end
|
132
|
+
Dir.glob("#{source_path}/roles/*.rb").each do |role|
|
133
|
+
role_obj = Chef::Role.new
|
134
|
+
role_obj.name File.basename(role, ".rb")
|
135
|
+
role_obj.from_file(role)
|
136
|
+
File.write("#{install_path}/roles/#{File.basename(role, ".rb")}.json", role_obj.to_json)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def install_data_bags(new_version, source_path, install_path)
|
141
|
+
FileUtils.mkdir_p("#{install_path}/data_bags")
|
142
|
+
Dir.glob("#{source_path}/data_bags/*").each do |data_bag|
|
143
|
+
next if !File.directory? data_bag
|
144
|
+
|
145
|
+
data_bag_name = File.basename(data_bag)
|
146
|
+
FileUtils.mkdir_p("#{install_path}/data_bags/#{data_bag_name}")
|
147
|
+
items = Dir.glob("#{data_bag}/*.json")
|
148
|
+
if !items.empty?
|
149
|
+
FileUtils.cp(items, "#{install_path}/data_bags/#{data_bag_name}")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def build(force = false)
|
155
|
+
current_link = "#{@storage_path}/current"
|
156
|
+
old_version = File.symlink?(current_link) && File.readlink(current_link)
|
157
|
+
|
158
|
+
new_version, source_path = pull_source()
|
159
|
+
install_path = File.expand_path("#{@storage_path}/#{new_version}")
|
160
|
+
|
161
|
+
if force || new_version != old_version
|
162
|
+
begin
|
163
|
+
install_cookbooks(new_version, source_path, install_path)
|
164
|
+
install_environments(new_version, source_path, install_path)
|
165
|
+
install_roles(new_version, source_path, install_path)
|
166
|
+
install_data_bags(new_version, source_path, install_path)
|
167
|
+
rescue
|
168
|
+
# Clean up the probably broken deploy install path if it got created.
|
169
|
+
# We don't care why it failed, so we pass the buck up.
|
170
|
+
FileUtils.rmdir(install_path) if File.directory?(install_path)
|
171
|
+
raise
|
172
|
+
end
|
173
|
+
|
174
|
+
tmplink = current_link + ".#{Process.pid}.lnk"
|
175
|
+
FileUtils.ln_s(new_version, tmplink)
|
176
|
+
File.rename(tmplink, current_link)
|
177
|
+
|
178
|
+
if old_version && File.directory?("#{@storage_path}/#{old_version}")
|
179
|
+
FileUtils.rm_rf("#{@storage_path}/#{old_version}")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fry-cook
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0.beta1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Graham Batty
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: chef
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '11'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: chef-zero
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: berkshelf
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.0.0.beta7
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.0.0.beta7
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-core
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.13.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.13.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-expectations
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.13.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.13.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-mocks
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.13.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.13.0
|
97
|
+
description: Not quite a chef yet, the fry cook knows only one menu.
|
98
|
+
email: graham@stormbrew.ca
|
99
|
+
executables:
|
100
|
+
- fry-cook
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- bin/fry-cook
|
105
|
+
- lib/fry_cook/version.rb
|
106
|
+
- lib/fry_cook/vagrant_plugin/hooks.rb
|
107
|
+
- lib/fry_cook/vagrant_plugin/config.rb
|
108
|
+
- lib/fry_cook/work_tree.rb
|
109
|
+
- lib/fry_cook/server.rb
|
110
|
+
- lib/fry_cook/vagrant_plugin.rb
|
111
|
+
- lib/fry_cook/.version.rb.swp
|
112
|
+
- lib/fry-cook.rb
|
113
|
+
- LICENSE
|
114
|
+
- README.md
|
115
|
+
homepage: https://www.github.com/stormbrew/fry-cook
|
116
|
+
licenses: []
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>'
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.3.1
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.0.3
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Not quite a chef yet, the fry cook knows only one menu.
|
138
|
+
test_files: []
|