fry-cook 0.2.0.beta1

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.
@@ -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.
@@ -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.
@@ -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
@@ -0,0 +1,3 @@
1
+ if defined? Vagrant
2
+ require 'fry_cook/vagrant_plugin'
3
+ end
@@ -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,3 @@
1
+ module FryCook
2
+ VERSION = "0.2.0.beta1"
3
+ 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: []