vagrant-cookbook-fetcher 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +29 -0
- data/README.md +62 -0
- data/lib/vagrant_cookbook_fetcher.rb +205 -0
- data/lib/vagrant_init.rb +1 -0
- metadata +50 -0
data/LICENSE
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Copyright (c) 2012, OmniTI Computer Consulting, Inc.
|
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
|
6
|
+
met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above
|
11
|
+
copyright notice, this list of conditions and the following
|
12
|
+
disclaimer in the documentation and/or other materials provided
|
13
|
+
with the distribution.
|
14
|
+
* Neither the name OmniTI Computer Consulting, Inc. nor the names
|
15
|
+
of its contributors may be used to endorse or promote products
|
16
|
+
derived from this software without specific prior written
|
17
|
+
permission.
|
18
|
+
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
20
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
21
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
22
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
25
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
26
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
27
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
28
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
vagrant-cookbook-fetcher
|
2
|
+
========================
|
3
|
+
|
4
|
+
A Vagrant plugin to automatically fetch cookbooks, roles, and such whenever you run vagrant provision, up or start.
|
5
|
+
|
6
|
+
## Behavior
|
7
|
+
|
8
|
+
Once you set a URL that provides a list of checkouts, this plugin will create two directory trees:
|
9
|
+
|
10
|
+
my-vagrant-project
|
11
|
+
|...Vagrantfile
|
12
|
+
|...checkouts
|
13
|
+
| |...checkout-foo
|
14
|
+
| |...checkout-bar
|
15
|
+
|...combined
|
16
|
+
|...roles
|
17
|
+
|...nodes
|
18
|
+
|...data_bags
|
19
|
+
|
20
|
+
The plugin will loop through the list of checkouts, perform a clone/checkout or pull/update to make sure the checkout exists in the 'checkouts' directory.
|
21
|
+
|
22
|
+
Next, the plugin creates the 'combined' directory. Each checkout that has a roles directory gets its roles symlinked to; likewise for data bags and nodes. This feature allows you to have roles defined in multiple checkouts, and used from your local project. In the event of name collisions, the later checkout wins. The links are specially constructed to be valid from within the VM, so long as the v-root remains mounted at /vagrant .
|
23
|
+
|
24
|
+
Finally, the plugin configures chef-solo, setting the cookbook path (to an ordered array of the checkouts's cookbooks directories), the roles path (to the combined path), and the databags path (to the combined path).
|
25
|
+
|
26
|
+
## Checkout List Format
|
27
|
+
|
28
|
+
git,src@src.omniti.com:~internal/chef/common,omniti-internal-common,multi-repo,chef.key
|
29
|
+
git,git@trac-il.omniti.net:myproject/support/chef,myproject-chef,master,AGENT
|
30
|
+
git,https://github.com/opscode-cookbooks/php.git,opscode-php/cookbooks/php,master,NONE
|
31
|
+
|
32
|
+
The fields are: VCS,repo address, directory name, branch, credentials
|
33
|
+
* VCS may be either 'git' or 'svn' (TODO).
|
34
|
+
* repo address is the identifier of the repository from which to obtain the checkout.
|
35
|
+
* directory name is the path under <vagrant-root>/checkouts to clone/checkout into. It may contain slashes.
|
36
|
+
* branch is the name of the git branch. Leave blank for svn (use repo address for svn branching)
|
37
|
+
* (this feature is TODO) credentials is the method to authenticate to the repo server. NONE means use no authentication. AGENT means to rely on a running ssh-agent to provide credentials. All other values are taken to specify the location of a SSH private key, relative to <vagrant-root>, that should be used with a GIT_SSH wrapper.
|
38
|
+
|
39
|
+
## Configuration
|
40
|
+
|
41
|
+
### config.auto_checkout.url
|
42
|
+
|
43
|
+
Default: none.
|
44
|
+
|
45
|
+
URL that replies with a CSV file containing the list of checkouts.
|
46
|
+
|
47
|
+
If absent, no fetch occurs.
|
48
|
+
|
49
|
+
### config.auto_checkout.disable
|
50
|
+
|
51
|
+
Default: false
|
52
|
+
|
53
|
+
If true, no checkout will be be run. This can be useful if you're provisioning frequently and making local changes to your recipes.
|
54
|
+
|
55
|
+
Even if the fetch is disabled, this plugin will still try to tell chef-solo about your cookbook, role, and data_bag paths, unless you override them.
|
56
|
+
|
57
|
+
## TODO
|
58
|
+
|
59
|
+
* Add svn support
|
60
|
+
* Actually respect the credentials column
|
61
|
+
* Make checkout list format less awful, add headers
|
62
|
+
* support chef, not just chef-solo
|
@@ -0,0 +1,205 @@
|
|
1
|
+
|
2
|
+
# http://vagrantup.com/v1/docs/extending/configuration.html
|
3
|
+
class CookbookFetcherConfig < Vagrant::Config::Base
|
4
|
+
attr_accessor :url
|
5
|
+
attr_accessor :disable
|
6
|
+
end
|
7
|
+
Vagrant.config_keys.register(:cookbook_fetcher) { CookbookFetcherConfig }
|
8
|
+
|
9
|
+
|
10
|
+
# This is a Vagrant middleware plugin
|
11
|
+
# http://vagrantup.com/v1/docs/extending/middleware.html
|
12
|
+
|
13
|
+
class CookbookFetcher
|
14
|
+
def initialize(app, env)
|
15
|
+
@app = app
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
|
20
|
+
if !env[:global_config].cookbook_fetcher.disable then
|
21
|
+
if !env[:global_config].cookbook_fetcher.url.nil? then
|
22
|
+
fetch_checkouts env
|
23
|
+
else
|
24
|
+
env[:ui].warn "No URL set for auto-checkout, skipping"
|
25
|
+
end
|
26
|
+
else
|
27
|
+
env[:ui].info "Auto-checkout disabled, skipping"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Continue daisy chain
|
31
|
+
@app.call(env)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def fetch_checkouts (env)
|
36
|
+
url = env[:global_config].cookbook_fetcher.url
|
37
|
+
env[:ui].info "Fetching checkout list from #{url}"
|
38
|
+
|
39
|
+
checkouts = fetch_checkout_list url
|
40
|
+
perform_checkouts checkouts
|
41
|
+
update_links checkouts
|
42
|
+
end
|
43
|
+
|
44
|
+
def fetch_checkout_list (url)
|
45
|
+
require 'open-uri'
|
46
|
+
|
47
|
+
checkouts = { :by_dir => {}, :cookbook_list => [] }
|
48
|
+
|
49
|
+
open(url, {:ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE }) do |resp|
|
50
|
+
resp.each do |line|
|
51
|
+
line.chomp!
|
52
|
+
if !line.empty? then
|
53
|
+
pieces = line.split(/,/)
|
54
|
+
branch = pieces[3]
|
55
|
+
dir = pieces[2]
|
56
|
+
|
57
|
+
# Build info hash
|
58
|
+
checkouts[:by_dir][dir] = {
|
59
|
+
:vcs => pieces[0],
|
60
|
+
:repo => pieces[1],
|
61
|
+
:dir => dir,
|
62
|
+
:branch => pieces[3],
|
63
|
+
:creds => pieces[4],
|
64
|
+
}
|
65
|
+
|
66
|
+
# Build cookbook list. Use first part of directory, and append cookbooks
|
67
|
+
checkouts[:cookbook_list].push 'checkouts/' + (dir.split('/'))[0] + '/cookbooks'
|
68
|
+
|
69
|
+
# Write cookbook order to a file, in case we are later disabled
|
70
|
+
File.open('.cookbook-order', 'w') do |f|
|
71
|
+
f.print(checkouts[:cookbook_list].join("\n"))
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
return checkouts
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
def perform_checkouts (checkouts)
|
83
|
+
|
84
|
+
if !Dir.exists?("checkouts") then Dir.mkdir("checkouts") end
|
85
|
+
|
86
|
+
Dir.chdir("checkouts") do
|
87
|
+
checkouts[:by_dir].each do |dir, info|
|
88
|
+
puts "Updating checkout '#{dir}'"
|
89
|
+
if info[:vcs] == 'git' then
|
90
|
+
|
91
|
+
if Dir.exists?(info[:dir]) then
|
92
|
+
# pull
|
93
|
+
Dir.chdir(info[:dir]) do
|
94
|
+
# TODO ignores git creds
|
95
|
+
cmd = "git checkout #{info[:branch]}"
|
96
|
+
unless system cmd then raise "Could not '#{cmd}'" end
|
97
|
+
cmd = "git pull"
|
98
|
+
unless system cmd then raise "Could not '#{cmd}'" end
|
99
|
+
end
|
100
|
+
else
|
101
|
+
# clone
|
102
|
+
cmd = "git clone -b #{info[:branch]} #{info[:repo]} #{info[:dir]}"
|
103
|
+
unless system cmd then raise "Could not '#{cmd}'" end
|
104
|
+
end
|
105
|
+
else
|
106
|
+
raise "Unsupported VCS '#{info[:vcs]}' in checkout list for entry '#{dir}'"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_links (checkouts)
|
113
|
+
things_to_link = ["roles", "nodes", "handlers", "data_bags"]
|
114
|
+
puts "Updating links to #{things_to_link.join(', ')}"
|
115
|
+
|
116
|
+
if !Dir.exists?("combined") then Dir.mkdir("combined") end
|
117
|
+
Dir.chdir("combined") do
|
118
|
+
|
119
|
+
# Create/clear the subdirs
|
120
|
+
things_to_link.each do |thing|
|
121
|
+
if !Dir.exists?(thing) then Dir.mkdir(thing) end
|
122
|
+
Dir.foreach(thing) do |file|
|
123
|
+
if FileTest.symlink?(file) then File.delete(file) end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Being careful to go in cookbook order, symlink the files
|
129
|
+
checkouts[:cookbook_list].each do |cookbook_dir|
|
130
|
+
checkout_dir = (cookbook_dir.split('/'))[1]
|
131
|
+
things_to_link.each do |thing|
|
132
|
+
co_thing_dir = "checkouts/#{checkout_dir}/#{thing}"
|
133
|
+
combined_dir = "combined/#{thing}"
|
134
|
+
if Dir.exists?(co_thing_dir) then
|
135
|
+
Dir.entries(co_thing_dir).grep(/\.(rb|json)$/).each do |file|
|
136
|
+
# Under vagrant, we see this directory as /vagrant/checkouts/foo/role/bar.rb
|
137
|
+
# Use -f so later checkouts can override earlier ones
|
138
|
+
cmd = "ln -sf /vagrant/#{co_thing_dir}/#{file} combined/#{thing}/#{file}"
|
139
|
+
unless system cmd then raise "Could not '#{cmd}'" end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
Vagrant.actions[:provision].insert(Vagrant::Action::General::Validate, CookbookFetcher)
|
150
|
+
# Note that :up includes :start ( see https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/action/builtin.rb )
|
151
|
+
Vagrant.actions[:start].insert(Vagrant::Action::General::Validate, CookbookFetcher)
|
152
|
+
|
153
|
+
|
154
|
+
# Injects auto-checkout-derived chef-solo config
|
155
|
+
class CookbookFetcherConfigureChef
|
156
|
+
def initialize(app, env)
|
157
|
+
@app = app
|
158
|
+
end
|
159
|
+
|
160
|
+
def call(env)
|
161
|
+
# Do this even if fetch is disabled
|
162
|
+
|
163
|
+
require 'pp'
|
164
|
+
# there has got to be a better way
|
165
|
+
provisioners_list = env[:vm].config.to_hash["keys"][:vm].provisioners
|
166
|
+
|
167
|
+
chef_solo = provisioners_list.find { |p| p.shortcut === :chef_solo }
|
168
|
+
if !chef_solo.nil? then
|
169
|
+
solo_cfg = chef_solo.config
|
170
|
+
|
171
|
+
if solo_cfg.roles_path.nil? then
|
172
|
+
solo_cfg.roles_path = "combined/roles"
|
173
|
+
else
|
174
|
+
env[:ui].warn "Auto-checkout is keeping your custom chef-solo role path"
|
175
|
+
end
|
176
|
+
|
177
|
+
if solo_cfg.data_bags_path.nil? then
|
178
|
+
solo_cfg.data_bags_path = "combined/data_bags"
|
179
|
+
else
|
180
|
+
env[:ui].warn "Auto-checkout is keeping your custom chef-solo data_bags path"
|
181
|
+
end
|
182
|
+
|
183
|
+
# Cookbooks has a default
|
184
|
+
if solo_cfg.cookbooks_path === ["cookbooks", [:vm, "cookbooks"]] then
|
185
|
+
# Read from filesystem
|
186
|
+
if !File.exists?(".cookbook-order") then
|
187
|
+
env[:ui].error "Auto-checkout could not a .cookbook-order file. You need to run provision with autocheckout enabled at least once (or else specify your own cookbook path)"
|
188
|
+
end
|
189
|
+
|
190
|
+
cbs = []
|
191
|
+
IO.readlines(".cookbook-order").each { |line| cbs.push line.chomp }
|
192
|
+
solo_cfg.cookbooks_path = cbs
|
193
|
+
else
|
194
|
+
env[:ui].warn "Auto-checkout is keeping your custom chef-solo cookbook path"
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
# Continue daisy chain
|
200
|
+
@app.call(env)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
Vagrant.actions[:provision].insert(Vagrant::Action::VM::Provision, CookbookFetcherConfigureChef)
|
205
|
+
Vagrant.actions[:start].insert(Vagrant::Action::VM::Provision, CookbookFetcherConfigureChef)
|
data/lib/vagrant_init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'vagrant_cookbook_fetcher'
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-cookbook-fetcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Clinton Wolfe
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-09 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Whenever you run start, up, or provision, this plugin will dynamically
|
15
|
+
fetch a list of checkouts from a URL; checkout each one; then create a combined
|
16
|
+
roles directory, with symlinks.
|
17
|
+
email: clinton@NOSPAM.omniti.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- LICENSE
|
23
|
+
- README.md
|
24
|
+
- lib/vagrant_init.rb
|
25
|
+
- lib/vagrant_cookbook_fetcher.rb
|
26
|
+
homepage: https://github.com/clintoncwolfe/vagrant-cookbook-fetcher
|
27
|
+
licenses: []
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 1.8.11
|
47
|
+
signing_key:
|
48
|
+
specification_version: 3
|
49
|
+
summary: Fetch your Chef cookbooks whenever you provision
|
50
|
+
test_files: []
|