fry-cook 0.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []