From 302f9ff0bb8e0f39c88fd5664ee3d711cb92f65a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 13 Jan 2011 21:02:26 -0800 Subject: [PATCH] Puppet provisioner can mount/configure module paths from local directory --- CHANGELOG.md | 16 +++---- lib/vagrant/provisioners/puppet.rb | 49 +++++++++++++++++++++- templates/locales/en.yml | 1 + test/vagrant/provisioners/puppet_test.rb | 53 +++++++++++++++++++++++- 4 files changed, 105 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 726c0fa19..d3efcc03d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,8 @@ ## 0.7.0 (unreleased) -The 0.7.0 betas will be merged into this one section upon final release. -I don't expect many changes. - -## 0.7.0.beta2 (January 13, 2010) - + - VirtualBox 4.0 support. Support for VirtualBox 3.2 is _dropped_, since + the API is so different. Stay with the 0.6.x series if you have VirtualBox + 3.2.x. - Puppet server provisioner. [GH-262] - Use numeric uid/gid in mounting shared folders to increase portability. [GH-252] - HTTP downloading follows redirects. [GH-163] @@ -28,17 +26,13 @@ I don't expect many changes. change is not backwards compatible. [GH-265] - Provisioners are now RVM-friendly, meaning if you installed chef or puppet with an RVM managed Ruby, Vagrant now finds then. [GH-254] - -## 0.7.0.beta (December 24, 2010) - - - VirtualBox 4.0 support. Support for VirtualBox 3.2 is _dropped_, since - the API is so different. Stay with the 0.6.x series if you have VirtualBox - 3.2.x. - Changed the unused host only network destroy mechanism to check for uselessness after the VM is destroyed. This should result in more accurate checks. - Networks are no longer disabled upon halt/destroy. With the above change, its unnecessary. + - Puppet supports `module_path` configuration to mount local modules directory + as a shared folder and configure puppet with it. [GH-270] ## 0.6.9 (December 21, 2010) diff --git a/lib/vagrant/provisioners/puppet.rb b/lib/vagrant/provisioners/puppet.rb index 1827bd4b8..2fa7e14ce 100644 --- a/lib/vagrant/provisioners/puppet.rb +++ b/lib/vagrant/provisioners/puppet.rb @@ -10,12 +10,14 @@ module Vagrant class Config < Vagrant::Config::Base attr_accessor :manifest_file attr_accessor :manifests_path + attr_accessor :module_path attr_accessor :pp_path attr_accessor :options def initialize @manifest_file = nil @manifests_path = "manifests" + @module_path = nil @pp_path = "/tmp/vagrant-puppet" @options = [] end @@ -32,20 +34,45 @@ module Vagrant manifest_file || "#{top.vm.box}.pp" end + # Returns the module paths as an array of paths expanded relative to the + # root path. + def expanded_module_paths + return [] if !module_path + + # Get all the paths and expand them relative to the root path, returning + # the array of expanded paths + paths = module_path + paths = [paths] if !paths.is_a?(Array) + paths.map do |path| + Pathname.new(path).expand_path(env.root_path) + end + end + def validate(errors) super + # Manifests path/file validation if !expanded_manifests_path.directory? errors.add(I18n.t("vagrant.provisioners.puppet.manifests_path_missing", :path => expanded_manifests_path)) - return + else + if !expanded_manifests_path.join(computed_manifest_file).file? + errors.add(I18n.t("vagrant.provisioners.puppet.manifest_missing", :manifest => computed_manifest_file)) + end end - errors.add(I18n.t("vagrant.provisioners.puppet.manifest_missing", :manifest => computed_manifest_file)) if !expanded_manifests_path.join(computed_manifest_file).file? + # Module paths validation + expanded_module_paths.each do |path| + if !path.directory? + errors.add(I18n.t("vagrant.provisioners.puppet.module_path_missing", :path => path)) + end + end end end def prepare + set_module_paths share_manifests + share_module_paths end def provision! @@ -58,6 +85,23 @@ module Vagrant env.config.vm.share_folder("manifests", config.pp_path, config.manifests_path) end + def share_module_paths + count = 0 + @module_paths.each do |from, to| + # Sorry for the cryptic key here, but VirtualBox has a strange limit on + # maximum size for it and its something small (around 10) + env.config.vm.share_folder("v-pp-m#{count}", to, from) + count += 1 + end + end + + def set_module_paths + @module_paths = {} + config.expanded_module_paths.each_with_index do |path, i| + @module_paths[path] = File.join(config.pp_path, "modules-#{i}") + end + end + def verify_binary(binary) vm.ssh.execute do |ssh| ssh.exec!("sudo -i which #{binary}", :error_class => PuppetError, :_key => :puppet_not_detected, :binary => binary) @@ -73,6 +117,7 @@ module Vagrant def run_puppet_client options = [config.options].flatten + options << "--modulepath '#{@module_paths.values.join(':')}'" if !@module_paths.empty? options << config.computed_manifest_file options = options.join(" ") diff --git a/templates/locales/en.yml b/templates/locales/en.yml index cb85db533..47fe41d82 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -475,6 +475,7 @@ en: running_puppet: "Running Puppet with %{manifest}..." manifest_missing: "The Puppet %{manifest} manifest is missing. You cannot configure this box." manifests_path_missing: "The manifests path specified for Puppet does not exist: %{path}" + module_path_missing: "The configured module path doesn't exist: %{path}" puppet_server: not_detected: |- diff --git a/test/vagrant/provisioners/puppet_test.rb b/test/vagrant/provisioners/puppet_test.rb index 8217707fa..68e2556cf 100644 --- a/test/vagrant/provisioners/puppet_test.rb +++ b/test/vagrant/provisioners/puppet_test.rb @@ -41,6 +41,20 @@ class PuppetProvisionerTest < Test::Unit::TestCase assert_equal "woot.pp", @config.computed_manifest_file end + should "return an empty array if no module path is set" do + @config.module_path = nil + assert_equal [], @config.expanded_module_paths + end + + should "return array of module paths expanded relative to root path" do + @config.module_path = "foo" + + result = @config.expanded_module_paths + assert result.is_a?(Array) + assert_equal 1, result.length + assert_equal File.expand_path(@config.module_path, @env.root_path), result[0].to_s + end + should "be valid" do @config.validate(@errors) assert @errors.errors.empty? @@ -63,11 +77,27 @@ class PuppetProvisionerTest < Test::Unit::TestCase @config.validate(@errors) assert !@errors.errors.empty? end + + should "be invalid if a specified module path doesn't exist" do + @config.module_path = "foo" + @config.validate(@errors) + assert !@errors.errors.empty? + end + + should "be valid if all module paths exist" do + @config.module_path = "foo" + @config.expanded_module_paths.first.mkdir + @config.validate(@errors) + assert @errors.errors.empty? + end end context "preparing" do should "share manifests" do - @action.expects(:share_manifests).once + pre_seq = sequence("prepare") + @action.expects(:set_module_paths).once.in_sequence(pre_seq) + @action.expects(:share_manifests).once.in_sequence(pre_seq) + @action.expects(:share_module_paths).once.in_sequence(pre_seq) @action.prepare end end @@ -96,6 +126,18 @@ class PuppetProvisionerTest < Test::Unit::TestCase end end + context "sharing module paths" do + should "share all the module paths" do + @config.module_path = ["foo", "bar"] + @config.expanded_module_paths.each_with_index do |path, i| + @env.config.vm.expects(:share_folder).with("v-pp-m#{i}", File.join(@config.pp_path, "modules-#{i}"), path) + end + + @action.set_module_paths + @action.share_module_paths + end + end + context "verifying binary" do setup do @ssh = mock("ssh") @@ -124,6 +166,7 @@ class PuppetProvisionerTest < Test::Unit::TestCase setup do @ssh = mock("ssh") @vm.ssh.stubs(:execute).yields(@ssh) + @action.set_module_paths end def expect_puppet_command(command) @@ -146,5 +189,13 @@ class PuppetProvisionerTest < Test::Unit::TestCase expect_puppet_command("puppet --modulepath modules --verbose #{@config.computed_manifest_file}") @action.run_puppet_client end + + should "cd into the pp_path and run puppet with module paths if set" do + @config.module_path = "foo" + expect_puppet_command("puppet --modulepath '#{File.join(@config.pp_path, 'modules-0')}' #{@config.computed_manifest_file}") + + @action.set_module_paths + @action.run_puppet_client + end end end