vagrant-berkshelf 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +18 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +18 -0
- data/CONTRIBUTING.md +44 -0
- data/Gemfile +35 -0
- data/Guardfile +16 -0
- data/LICENSE.txt +13 -0
- data/README.md +35 -0
- data/Thorfile +58 -0
- data/lib/berkshelf/vagrant.rb +45 -0
- data/lib/berkshelf/vagrant/action.rb +63 -0
- data/lib/berkshelf/vagrant/action/clean.rb +28 -0
- data/lib/berkshelf/vagrant/action/configure_chef.rb +28 -0
- data/lib/berkshelf/vagrant/action/install.rb +71 -0
- data/lib/berkshelf/vagrant/action/load_shelf.rb +50 -0
- data/lib/berkshelf/vagrant/action/set_ui.rb +17 -0
- data/lib/berkshelf/vagrant/action/upload.rb +50 -0
- data/lib/berkshelf/vagrant/config.rb +91 -0
- data/lib/berkshelf/vagrant/env.rb +26 -0
- data/lib/berkshelf/vagrant/env_helpers.rb +64 -0
- data/lib/berkshelf/vagrant/errors.rb +33 -0
- data/lib/berkshelf/vagrant/plugin.rb +42 -0
- data/lib/berkshelf/vagrant/version.rb +5 -0
- data/lib/vagrant-berkshelf.rb +1 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/unit/berkshelf/vagrant/config_spec.rb +97 -0
- data/spec/unit/berkshelf/vagrant/errors_spec.rb +12 -0
- data/spec/unit/berkshelf/vagrant_spec.rb +25 -0
- data/vagrant-berkshelf.gemspec +36 -0
- metadata +230 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
module Action
|
4
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
5
|
+
class Install
|
6
|
+
include Berkshelf::Vagrant::EnvHelpers
|
7
|
+
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
if provision_disabled?(env)
|
14
|
+
env[:berkshelf].ui.info "Skipping Berkshelf with --no-provision"
|
15
|
+
|
16
|
+
return @app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
unless berkshelf_enabled?(env)
|
20
|
+
if File.exist?(env[:global_config].berkshelf.berksfile_path)
|
21
|
+
warn_disabled_but_berksfile_exists(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
return @app.call(env)
|
25
|
+
end
|
26
|
+
|
27
|
+
env[:berkshelf].berksfile = Berkshelf::Berksfile.from_file(env[:global_config].berkshelf.berksfile_path)
|
28
|
+
|
29
|
+
if chef_solo?(env)
|
30
|
+
install(env)
|
31
|
+
end
|
32
|
+
|
33
|
+
@app.call(env)
|
34
|
+
rescue Berkshelf::BerkshelfError => e
|
35
|
+
raise Berkshelf::VagrantWrapperError.new(e)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def install(env)
|
41
|
+
check_vagrant_version(env)
|
42
|
+
env[:berkshelf].ui.info "Updating Vagrant's berkshelf: '#{env[:berkshelf].shelf}'"
|
43
|
+
opts = {
|
44
|
+
path: env[:berkshelf].shelf
|
45
|
+
}.merge(env[:global_config].berkshelf.to_hash).symbolize_keys!
|
46
|
+
env[:berkshelf].berksfile.install(opts)
|
47
|
+
end
|
48
|
+
|
49
|
+
def warn_disabled_but_berksfile_exists(env)
|
50
|
+
env[:berkshelf].ui.warn "Berkshelf plugin is disabled but a Berksfile was found at" +
|
51
|
+
" your configured path: #{env[:global_config].berkshelf.berksfile_path}"
|
52
|
+
env[:berkshelf].ui.warn "Enable the Berkshelf plugin by setting 'config.berkshelf.enabled = true'" +
|
53
|
+
" in your vagrant config"
|
54
|
+
end
|
55
|
+
|
56
|
+
def check_vagrant_version(env)
|
57
|
+
unless Solve::Constraint.new(">= 1.1").satisfies?(::Vagrant::VERSION)
|
58
|
+
raise Berkshelf::VagrantWrapperError.new(RuntimeError.new("vagrant-berkshelf requires Vagrant 1.1 or later."))
|
59
|
+
end
|
60
|
+
|
61
|
+
unless Solve::Constraint.new(::Berkshelf::Vagrant::TESTED_CONSTRAINT).satisfies?(::Vagrant::VERSION)
|
62
|
+
env[:berkshelf].ui.warn "This version of the Berkshelf plugin has not been fully tested on this version of Vagrant."
|
63
|
+
env[:berkshelf].ui.warn "You should check for a newer version of vagrant-berkshelf."
|
64
|
+
env[:berkshelf].ui.warn "If you encounter any errors with this version, please report them at https://github.com/RiotGames/vagrant-berkshelf/issues"
|
65
|
+
env[:berkshelf].ui.warn "You can also join the discussion in #berkshelf on Freenode."
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
module Action
|
4
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
5
|
+
class LoadShelf
|
6
|
+
include Berkshelf::Vagrant::EnvHelpers
|
7
|
+
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
unless berkshelf_enabled?(env)
|
14
|
+
return @app.call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
shelf = load_shelf
|
18
|
+
|
19
|
+
if shelf.nil?
|
20
|
+
shelf = cache_shelf(Berkshelf::Vagrant.mkshelf)
|
21
|
+
end
|
22
|
+
|
23
|
+
env[:berkshelf].shelf = shelf
|
24
|
+
|
25
|
+
@app.call(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [String] path
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def cache_shelf(path)
|
32
|
+
FileUtils.mkdir_p(File.dirname(path))
|
33
|
+
|
34
|
+
File.open(cache_file, 'w+') do |f|
|
35
|
+
f.write(path)
|
36
|
+
end
|
37
|
+
|
38
|
+
path
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String, nil]
|
42
|
+
def load_shelf
|
43
|
+
return nil unless File.exist?(cache_file)
|
44
|
+
|
45
|
+
File.read(cache_file).chomp
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
module Action
|
4
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
5
|
+
class SetUI
|
6
|
+
def initialize(app, env)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
Berkshelf.ui = env[:berkshelf].ui
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
module Action
|
4
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
5
|
+
class Upload
|
6
|
+
include Berkshelf::Vagrant::EnvHelpers
|
7
|
+
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
if provision_disabled?(env)
|
14
|
+
return @app.call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
unless berkshelf_enabled?(env)
|
18
|
+
return @app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
if chef_client?(env)
|
22
|
+
upload(env)
|
23
|
+
end
|
24
|
+
|
25
|
+
@app.call(env)
|
26
|
+
rescue Berkshelf::BerkshelfError => e
|
27
|
+
raise Berkshelf::VagrantWrapperError.new(e)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def upload(env)
|
33
|
+
provisioners(:chef_client, env).each do |provisioner|
|
34
|
+
env[:berkshelf].ui.info "Uploading cookbooks to '#{provisioner.config.chef_server_url}'"
|
35
|
+
env[:berkshelf].berksfile.upload(
|
36
|
+
server_url: provisioner.config.chef_server_url,
|
37
|
+
client_name: env[:berkshelf].config.chef.node_name,
|
38
|
+
client_key: env[:berkshelf].config.chef.client_key,
|
39
|
+
ssl: {
|
40
|
+
verify: env[:berkshelf].config.ssl.verify
|
41
|
+
},
|
42
|
+
force: true,
|
43
|
+
freeze: false
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
4
|
+
class Config < ::Vagrant.plugin("2", :config)
|
5
|
+
# @return [String]
|
6
|
+
# path to the Berksfile to use with Vagrant
|
7
|
+
attr_reader :berksfile_path
|
8
|
+
|
9
|
+
# @return [Boolean]
|
10
|
+
# disable of use Berks in Vagrant
|
11
|
+
attr_accessor :enabled
|
12
|
+
|
13
|
+
# @return [Array<Symbol>]
|
14
|
+
# only cookbooks in these groups will be installed and copied to
|
15
|
+
# Vagrant's shelf
|
16
|
+
attr_accessor :only
|
17
|
+
|
18
|
+
# @return [Array<Symbol>]
|
19
|
+
# cookbooks in all other groups except for these will be installed
|
20
|
+
# and copied to Vagrant's shelf
|
21
|
+
attr_accessor :except
|
22
|
+
|
23
|
+
# @return [String]
|
24
|
+
# the Chef node name (client name) to use to authenticate with the remote
|
25
|
+
# chef server to upload cookbooks when using the chef client provisioner
|
26
|
+
attr_accessor :node_name
|
27
|
+
|
28
|
+
# @return [String]
|
29
|
+
# a filepath to a chef client key to use to authenticate with the remote
|
30
|
+
# chef server to upload cookbooks when using the chef client provisioner
|
31
|
+
attr_accessor :client_key
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
super
|
35
|
+
|
36
|
+
@berksfile_path = File.join(Dir.pwd, Berkshelf::DEFAULT_FILENAME)
|
37
|
+
@except = Array.new
|
38
|
+
@only = Array.new
|
39
|
+
@node_name = Berkshelf::Config.instance.chef.node_name
|
40
|
+
@client_key = Berkshelf::Config.instance.chef.client_key
|
41
|
+
@enabled = File.exist?(@berksfile_path)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [String] value
|
45
|
+
def berksfile_path=(value)
|
46
|
+
@berksfile_path = File.expand_path(value)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param [String] value
|
50
|
+
def client_key=(value)
|
51
|
+
@client_key = File.expand_path(value)
|
52
|
+
end
|
53
|
+
|
54
|
+
alias_method :to_hash, :instance_variables_hash
|
55
|
+
|
56
|
+
def validate(machine)
|
57
|
+
errors = Array.new
|
58
|
+
|
59
|
+
unless [TrueClass, FalseClass].include?(enabled.class)
|
60
|
+
errors << "A value for berkshelf.enabled can be true or false."
|
61
|
+
end
|
62
|
+
|
63
|
+
if enabled
|
64
|
+
if machine.config.berkshelf.berksfile_path.nil?
|
65
|
+
errors << "berkshelf.berksfile_path cannot be nil."
|
66
|
+
end
|
67
|
+
|
68
|
+
unless File.exist?(machine.config.berkshelf.berksfile_path)
|
69
|
+
errors << "No Berskfile was found at #{machine.config.berkshelf.berksfile_path}."
|
70
|
+
end
|
71
|
+
|
72
|
+
if !except.empty? && !only.empty?
|
73
|
+
errors << "A value for berkshelf.empty and berkshelf.only cannot both be defined."
|
74
|
+
end
|
75
|
+
|
76
|
+
if machine.env.config_global.vm.provisioners.any? { |prov| prov.name == :chef_client }
|
77
|
+
if machine.config.berkshelf.node_name.nil?
|
78
|
+
errors << "A configuration must be set for chef.node_name when using the chef_client provisioner. Run 'berks configure' or edit your configuration."
|
79
|
+
end
|
80
|
+
|
81
|
+
if machine.config.berkshelf.client_key.nil?
|
82
|
+
errors << "A configuration must be set for chef.client_key when using the chef_client provisioner. Run 'berks configure' or edit your configuration."
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
{ "berkshelf configuration" => errors }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
4
|
+
#
|
5
|
+
# Environment data to build up and persist through the middleware chain
|
6
|
+
class Env
|
7
|
+
# @return [Vagrant::UI::Colored]
|
8
|
+
attr_accessor :ui
|
9
|
+
# @return [Berkshelf::Berksfile]
|
10
|
+
attr_accessor :berksfile
|
11
|
+
# @return [String]
|
12
|
+
attr_accessor :shelf
|
13
|
+
# @return [Berkshelf::Config]
|
14
|
+
attr_accessor :config
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
if Gem::Version.new(::Vagrant::VERSION) >= Gem::Version.new("1.2")
|
18
|
+
@ui = ::Vagrant::UI::Colored.new.scope('Berkshelf')
|
19
|
+
else
|
20
|
+
@ui = ::Vagrant::UI::Colored.new('Berkshelf')
|
21
|
+
end
|
22
|
+
@config = Berkshelf::Config.instance
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
4
|
+
#
|
5
|
+
# A module of common helper functions that can be mixed into Berkshelf::Vagrant actions
|
6
|
+
module EnvHelpers
|
7
|
+
# A file to persist vagrant-berkshelf specific information in between
|
8
|
+
# Vagrant runs.
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
def cache_file
|
12
|
+
File.join('.vagrant', 'berkshelf')
|
13
|
+
end
|
14
|
+
|
15
|
+
# Filter all of the provisioners of the given vagrant environment with the given name
|
16
|
+
#
|
17
|
+
# @param [Symbol] name
|
18
|
+
# name of provisioner to filter
|
19
|
+
# @param [Vagrant::Environment, Hash] env
|
20
|
+
# environment to inspect
|
21
|
+
#
|
22
|
+
# @return [Array]
|
23
|
+
def provisioners(name, env)
|
24
|
+
env[:machine].config.vm.provisioners.select { |prov| prov.name == name }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Determine if the given vagrant environment contains a chef_solo provisioner
|
28
|
+
#
|
29
|
+
# @param [Vagrant::Environment] env
|
30
|
+
#
|
31
|
+
# @return [Boolean]
|
32
|
+
def chef_solo?(env)
|
33
|
+
provisioners(:chef_solo, env).any?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Determine if the given vagrant environment contains a chef_client provisioner
|
37
|
+
#
|
38
|
+
# @param [Vagrant::Environment] env
|
39
|
+
#
|
40
|
+
# @return [Boolean]
|
41
|
+
def chef_client?(env)
|
42
|
+
provisioners(:chef_client, env).any?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Determine if the Berkshelf plugin should be run for the given environment
|
46
|
+
#
|
47
|
+
# @param [Vagrant::Environment] env
|
48
|
+
#
|
49
|
+
# @return [Boolean]
|
50
|
+
def berkshelf_enabled?(env)
|
51
|
+
env[:global_config].berkshelf.enabled
|
52
|
+
end
|
53
|
+
|
54
|
+
# Determine if --no-provision was specified
|
55
|
+
#
|
56
|
+
# @param [Vagrant::Environment] env
|
57
|
+
#
|
58
|
+
# @return [Boolean]
|
59
|
+
def provision_disabled?(env)
|
60
|
+
env.has_key?(:provision_enabled) && !env[:provision_enabled]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'vagrant/errors'
|
2
|
+
|
3
|
+
module Berkshelf
|
4
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
5
|
+
#
|
6
|
+
# A wrapper for a BerkshelfError for Vagrant. All Berkshelf exceptions should be
|
7
|
+
# wrapped in this proxy object so they are properly handled when Vagrant encounters
|
8
|
+
# an exception.
|
9
|
+
#
|
10
|
+
# @example wrapping an error encountered within the Vagrant plugin
|
11
|
+
# rescue BerkshelfError => e
|
12
|
+
# VagrantWrapperError.new(e)
|
13
|
+
# end
|
14
|
+
class VagrantWrapperError < ::Vagrant::Errors::VagrantError
|
15
|
+
# @param [BerkshelfError]
|
16
|
+
attr_reader :original
|
17
|
+
|
18
|
+
# @param [BerkshelfError] original
|
19
|
+
def initialize(original)
|
20
|
+
@original = original
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"#{original.class}: #{original.to_s}"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def method_missing(fun, *args, &block)
|
30
|
+
original.send(fun, *args, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
module Vagrant
|
3
|
+
# @author Jamie Winsor <reset@riotgames.com>
|
4
|
+
TESTED_CONSTRAINT="<= 1.2.1"
|
5
|
+
class Plugin < ::Vagrant.plugin("2")
|
6
|
+
class << self
|
7
|
+
def provision(hook)
|
8
|
+
hook.after(::Vagrant::Action::Builtin::Provision, Berkshelf::Vagrant::Action.upload)
|
9
|
+
hook.after(::Vagrant::Action::Builtin::Provision, Berkshelf::Vagrant::Action.install)
|
10
|
+
|
11
|
+
if ::VagrantPlugins.const_defined?(:AWS)
|
12
|
+
hook.after(::VagrantPlugins::AWS::Action::TimedProvision, Berkshelf::Vagrant::Action.upload)
|
13
|
+
hook.after(::VagrantPlugins::AWS::Action::TimedProvision, Berkshelf::Vagrant::Action.install)
|
14
|
+
end
|
15
|
+
|
16
|
+
hook.before(::Vagrant::Action::Builtin::ConfigValidate, Berkshelf::Vagrant::Action.setup)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
name "berkshelf"
|
21
|
+
description <<-DESC
|
22
|
+
Automatically make available cookbooks to virtual machines provisioned by Chef Solo
|
23
|
+
or Chef Client using Berkshelf.
|
24
|
+
DESC
|
25
|
+
|
26
|
+
action_hook(:berkshelf_provision, :machine_action_up, &method(:provision))
|
27
|
+
action_hook(:berkshelf_provision, :machine_action_reload, &method(:provision))
|
28
|
+
action_hook(:berkshelf_provision, :machine_action_provision, &method(:provision))
|
29
|
+
|
30
|
+
action_hook(:berkshelf_cleanup, :machine_action_destroy) do |hook|
|
31
|
+
# @todo this should be appended to the middleware stack instead of hooked in after the
|
32
|
+
# Virtualbox specific destroy step but there is a bug in Vagrant (1.1.0) which
|
33
|
+
# causes appended middleware to run multiple times.
|
34
|
+
hook.after(VagrantPlugins::ProviderVirtualBox::Action::DestroyUnusedNetworkInterfaces, Berkshelf::Vagrant::Action.clean)
|
35
|
+
end
|
36
|
+
|
37
|
+
config(:berkshelf) do
|
38
|
+
Berkshelf::Vagrant::Config
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|