diff --git a/plugins/provisioners/puppet/config/puppet.rb b/plugins/provisioners/puppet/config/puppet.rb index 1810b989b..99b06face 100644 --- a/plugins/provisioners/puppet/config/puppet.rb +++ b/plugins/provisioners/puppet/config/puppet.rb @@ -1,11 +1,18 @@ module VagrantPlugins module Puppet module Config - class Puppet < Vagrant.plugin("2", :config) + class Puppet < Vagrant.plugin("2", :config) + + # The path to Puppet's bin/ directory. + # @return [String] + attr_accessor :binary_path + attr_accessor :facter attr_accessor :hiera_config_path attr_accessor :manifest_file attr_accessor :manifests_path + attr_accessor :environment + attr_accessor :environment_path attr_accessor :module_path attr_accessor :options attr_accessor :synced_folder_type @@ -15,15 +22,18 @@ module VagrantPlugins def initialize super - @hiera_config_path = UNSET_VALUE - @manifest_file = UNSET_VALUE - @manifests_path = UNSET_VALUE - @module_path = UNSET_VALUE - @options = [] - @facter = {} + @binary_path = UNSET_VALUE + @hiera_config_path = UNSET_VALUE + @manifest_file = UNSET_VALUE + @manifests_path = UNSET_VALUE + @environment = UNSET_VALUE + @environment_path = UNSET_VALUE + @module_path = UNSET_VALUE + @options = [] + @facter = {} @synced_folder_type = UNSET_VALUE - @temp_dir = UNSET_VALUE - @working_directory = UNSET_VALUE + @temp_dir = UNSET_VALUE + @working_directory = UNSET_VALUE end def nfs=(value) @@ -41,28 +51,49 @@ module VagrantPlugins def merge(other) super.tap do |result| result.facter = @facter.merge(other.facter) + result.environment_path = @facter.merge(other.environment_path) + result.environment = @facter.merge(other.environment) end end def finalize! super - if @manifests_path == UNSET_VALUE + if @environment_path == UNSET_VALUE && @manifests_path == UNSET_VALUE + #If both are unset, assume 'manifests' mode for now. TBD: Switch to environments by default? @manifests_path = [:host, "manifests"] end - if @manifests_path && !@manifests_path.is_a?(Array) + # If the paths are just strings, assume they are 'host' paths (rather than guest) + if @environment_path != UNSET_VALUE && !@environment_path.is_a?(Array) + @environment_path = [:host, @environment_path] + end + if @manifests_path != UNSET_VALUE && !@manifests_path.is_a?(Array) @manifests_path = [:host, @manifests_path] end - - @manifests_path[0] = @manifests_path[0].to_sym - @hiera_config_path = nil if @hiera_config_path == UNSET_VALUE - @manifest_file = "default.pp" if @manifest_file == UNSET_VALUE - @module_path = nil if @module_path == UNSET_VALUE - @synced_folder_type = nil if @synced_folder_type == UNSET_VALUE - @temp_dir = "/tmp/vagrant-puppet" if @temp_dir == UNSET_VALUE - @working_directory = nil if @working_directory == UNSET_VALUE + + if @environment_path == UNSET_VALUE + @manifests_path[0] = @manifests_path[0].to_sym + @environment_path = nil + @manifest_file = "default.pp" if @manifest_file == UNSET_VALUE + else + @environment_path[0] = @environment_path[0].to_sym + @environment = "production" if @environment == UNSET_VALUE + if @manifests_path == UNSET_VALUE + @manifests_path = nil + end + if @manifest_file == UNSET_VALUE + @manifest_file = nil + end + end + + @binary_path = nil if @binary_path == UNSET_VALUE + @module_path = nil if @module_path == UNSET_VALUE + @synced_folder_type = nil if @synced_folder_type == UNSET_VALUE + @temp_dir = "/tmp/vagrant-puppet" if @temp_dir == UNSET_VALUE + @working_directory = nil if @working_directory == UNSET_VALUE + end # Returns the module paths as an array of paths expanded relative to the @@ -86,7 +117,7 @@ module VagrantPlugins this_expanded_module_paths = expanded_module_paths(machine.env.root_path) # Manifests path/file validation - if manifests_path[0].to_sym == :host + if manifests_path != nil && manifests_path[0].to_sym == :host expanded_path = Pathname.new(manifests_path[1]). expand_path(machine.env.root_path) if !expanded_path.directory? @@ -99,8 +130,27 @@ module VagrantPlugins manifest: expanded_manifest_file.to_s) end end + elsif environment_path != nil && environment_path[0].to_sym == :host + # Environments path/file validation + expanded_path = Pathname.new(environment_path[1]). + expand_path(machine.env.root_path) + if !expanded_path.directory? + errors << I18n.t("vagrant.provisioners.puppet.environment_path_missing", + path: expanded_path.to_s) + else + expanded_environment_file = expanded_path.join(environment) + if !expanded_environment_file.file? && !expanded_environment_file.directory? + errors << I18n.t("vagrant.provisioners.puppet.environment_missing", + environment: environment.to_s, + environment_path: expanded_path.to_s) + end + end end + if environment_path == nil && manifests_path == nil + errors << "Please specify either a Puppet environment_path + environment (preferred) or manifests_path (deprecated)." + end + # Module paths validation this_expanded_module_paths.each do |path| if !path.directory? @@ -108,7 +158,6 @@ module VagrantPlugins path: path) end end - { "puppet provisioner" => errors } end end diff --git a/plugins/provisioners/puppet/plugin.rb b/plugins/provisioners/puppet/plugin.rb index 362a1c421..4d2b74bbe 100644 --- a/plugins/provisioners/puppet/plugin.rb +++ b/plugins/provisioners/puppet/plugin.rb @@ -10,22 +10,22 @@ module VagrantPlugins DESC config(:puppet, :provisioner) do - require File.expand_path("../config/puppet", __FILE__) + require_relative "config/puppet" Config::Puppet end config(:puppet_server, :provisioner) do - require File.expand_path("../config/puppet_server", __FILE__) + require_relative "config/puppet_server" Config::PuppetServer end provisioner(:puppet) do - require File.expand_path("../provisioner/puppet", __FILE__) + require_relative "provisioner/puppet" Provisioner::Puppet end provisioner(:puppet_server) do - require File.expand_path("../provisioner/puppet_server", __FILE__) + require_relative "provisioner/puppet_server" Provisioner::PuppetServer end end diff --git a/plugins/provisioners/puppet/provisioner/puppet.rb b/plugins/provisioners/puppet/provisioner/puppet.rb index c1e01c966..00cc1554c 100644 --- a/plugins/provisioners/puppet/provisioner/puppet.rb +++ b/plugins/provisioners/puppet/provisioner/puppet.rb @@ -20,7 +20,6 @@ module VagrantPlugins # Calculate the paths we're going to use based on the environment root_path = @machine.env.root_path @expanded_module_paths = @config.expanded_module_paths(root_path) - @manifest_file = File.join(manifests_guest_path, @config.manifest_file) # Setup the module paths @module_paths = [] @@ -33,11 +32,22 @@ module VagrantPlugins folder_opts[:type] = @config.synced_folder_type if @config.synced_folder_type folder_opts[:owner] = "root" if !@config.synced_folder_type - # Share the manifests directory with the guest - if @config.manifests_path[0].to_sym == :host - root_config.vm.synced_folder( - File.expand_path(@config.manifests_path[1], root_path), - manifests_guest_path, folder_opts) + if @config.environment_path.is_a?(Array) + # Share the environments directory with the guest + if @config.environment_path[0].to_sym == :host + root_config.vm.synced_folder( + File.expand_path(@config.environment_path[1], root_path), + environments_guest_path, folder_opts) + end + end + if @config.manifest_file + @manifest_file = File.join(manifests_guest_path, @config.manifest_file) + # Share the manifests directory with the guest + if @config.manifests_path[0].to_sym == :host + root_config.vm.synced_folder( + File.expand_path(@config.manifests_path[1], root_path), + manifests_guest_path, folder_opts) + end end # Share the module paths @@ -46,6 +56,24 @@ module VagrantPlugins end end + def parse_environment_metadata + # Parse out the environment manifest path since puppet apply doesnt do that for us. + environment_conf = File.join(environments_guest_path, @config.environment, "environment.conf") + if @machine.communicate.test("test -e #{environment_conf}", sudo: true) + conf = @machine.communicate.sudo("cat #{environment_conf}") do | type, data| + if type == :stdout + data.each_line do |line| + if line =~ /^\s*manifest\s+=\s+([^\s]+)/ + @manifest_file = $1 + @manifest_file.gsub! '$basemodulepath:', "#{environments_guest_path}/#{@config.environment}/" + @logger.debug("Using manifest from environment.conf: #{@manifest_file}") + end + end + end + end + end + end + def provision # If the machine has a wait for reboot functionality, then # do that (primarily Windows) @@ -53,11 +81,19 @@ module VagrantPlugins @machine.guest.capability(:wait_for_reboot) end + # In environment mode we still need to specify a manifest file, if its not, use the one from env config if specified. + if !@manifest_file + @manifest_file = "#{environments_guest_path}/#{@config.environment}/manifests/site.pp" + parse_environment_metadata + end # Check that the shared folders are properly shared check = [] - if @config.manifests_path[0] == :host + if @config.manifests_path.is_a?(Array) && @config.manifests_path[0] == :host check << manifests_guest_path end + if @config.environment_path.is_a?(Array) && @config.environment_path[0] == :host + check << environments_guest_path + end @module_paths.each do |host_path, guest_path| check << guest_path end @@ -71,7 +107,7 @@ module VagrantPlugins verify_shared_folders(check) # Verify Puppet is installed and run it - verify_binary("puppet") + verify_binary(puppet_binary_path("puppet")) # Upload Hiera configuration if we have it @hiera_config_path = nil @@ -96,12 +132,32 @@ module VagrantPlugins end end + def environments_guest_path + if config.environment_path[0] == :host + # The path is on the host, so point to where it is shared + File.join(config.temp_dir, "environments") + else + # The path is on the VM, so just point directly to it + config.environment_path[1] + end + end + + # Returns the path to the Puppet binary, taking into account the + # `binary_path` configuration option. + def puppet_binary_path(binary) + return binary if !@config.binary_path + return File.join(@config.binary_path, binary) + end + def verify_binary(binary) - @machine.communicate.sudo( - "which #{binary}", - error_class: PuppetError, - error_key: :not_detected, - binary: binary) + if !machine.communicate.test("sh -c 'command -v #{binary}'") + @config.binary_path = "/opt/puppetlabs/bin/" + @machine.communicate.sudo( + "test -x /opt/puppetlabs/bin/#{binary}", + error_class: PuppetError, + error_key: :not_detected, + binary: binary) + end end def run_puppet_apply @@ -129,8 +185,14 @@ module VagrantPlugins options << "--color=false" end - options << "--manifestdir #{manifests_guest_path}" options << "--detailed-exitcodes" + if config.environment_path + options << "--environmentpath #{environments_guest_path}/" + options << "--environment #{@config.environment}" + else + options << "--manifestdir #{manifests_guest_path}" + end + options << @manifest_file options = options.join(" ") @@ -150,7 +212,7 @@ module VagrantPlugins facter = "#{facts.join(" ")} " end - command = "#{facter}puppet apply #{options}" + command = "#{facter} #{config.binary_path}puppet apply #{options}" if config.working_directory if windows? command = "cd #{config.working_directory}; if (`$?) \{ #{command} \}" @@ -159,9 +221,15 @@ module VagrantPlugins end end - @machine.ui.info(I18n.t( - "vagrant.provisioners.puppet.running_puppet", - manifest: config.manifest_file)) + if config.environment_path + @machine.ui.info(I18n.t( + "vagrant.provisioners.puppet.running_puppet_env", + environment: config.environment)) + else + @machine.ui.info(I18n.t( + "vagrant.provisioners.puppet.running_puppet", + manifest: config.manifest_file)) + end opts = { elevated: true, diff --git a/templates/locales/en.yml b/templates/locales/en.yml index a7b25ea40..554e6a01c 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1854,11 +1854,17 @@ en: installed on this guest. Puppet provisioning can not continue without Puppet properly installed. running_puppet: "Running Puppet with %{manifest}..." + running_puppet_env: "Running Puppet with environment %{environment}..." manifest_missing: |- The configured Puppet manifest is missing. Please specify a path to an existing manifest: %{manifest} + environment_missing: |- + The configured Puppet environment folder %{environment} was not found in the + specified environmentpath %{environmentpath}. + Please specify a path to an existing Puppet directory environment. + environment_path_missing: "The environment path specified for Puppet does not exist: %{path}" manifests_path_missing: "The manifests path specified for Puppet does not exist: %{path}" missing_shared_folders: |- Shared folders that Puppet requires are missing on the virtual machine.