vagrant-berkshelf 1.2.0

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