require "log4r" require "vagrant" module VagrantPlugins module CFEngine class Provisioner < Vagrant.plugin("2", :provisioner) def provision if @machine.config.vm.communicator == :winrm raise Vagrant::Errors::ProvisionerWinRMUnsupported, name: "cfengine" end @logger = Log4r::Logger.new("vagrant::plugins::cfengine") @logger.info("Checking for CFEngine installation...") handle_cfengine_installation if @config.files_path @machine.ui.info(I18n.t("vagrant.cfengine_installing_files_path")) install_files(Pathname.new(@config.files_path).expand_path(@machine.env.root_path)) end handle_cfengine_bootstrap if @config.mode == :bootstrap if @config.mode == :single_run # Just let people know @machine.ui.info(I18n.t("vagrant.cfengine_single_run")) end if @config.run_file @machine.ui.info(I18n.t("vagrant.cfengine_single_run_execute")) path = Pathname.new(@config.run_file).expand_path(@machine.env.root_path) machine.communicate.upload(path.to_s, @config.upload_path) cfagent("-KI -f #{@config.upload_path}#{cfagent_classes_args}#{cfagent_extra_args}") end end protected # This runs cf-agent with the given arguments. def cfagent(args, options=nil) options ||= {} command = "/var/cfengine/bin/cf-agent #{args}" @machine.communicate.sudo(command, error_check: options[:error_check]) do |type, data| if [:stderr, :stdout].include?(type) # Output the data with the proper color based on the stream. color = type == :stdout ? :green : :red @machine.ui.info( data, color: color, new_line: false, prefix: false) end end end # Returns the arguments for the classes configuration if they are # set. # # @return [String] def cfagent_classes_args return "" if !@config.classes args = @config.classes.map { |c| "-D#{c}" }.join(" ") return " #{args}" end # Extra arguments for calles to cf-agent. # # @return [String] def cfagent_extra_args return "" if !@config.extra_agent_args return " #{@config.extra_agent_args}" end # This handles checking if the CFEngine installation needs to # be bootstrapped, and bootstraps if it does. def handle_cfengine_bootstrap @logger.info("Bootstrapping CFEngine...") if !@machine.guest.capability(:cfengine_needs_bootstrap, @config) @machine.ui.info(I18n.t("vagrant.cfengine_no_bootstrap")) return end # Needs bootstrap, let's determine the parameters policy_server_address = @config.policy_server_address if !policy_server_address policy_server_address = @machine.guest.capability(:read_ip_address) raise Vagrant::Errors::CFEngineCantAutodetectIP if !policy_server_address @machine.ui.info(I18n.t("vagrant.cfengine_detected_ip", address: policy_server_address)) end @machine.ui.info(I18n.t("vagrant.cfengine_bootstrapping", policy_server: policy_server_address)) result = cfagent("--bootstrap #{policy_server_address}", error_check: false) raise Vagrant::Errors::CFEngineBootstrapFailed if result != 0 # Policy hubs need to do additional things before they're ready # to accept agents. Force that run now... if @config.am_policy_hub @machine.ui.info(I18n.t("vagrant.cfengine_bootstrapping_policy_hub")) cfagent("-KI -f /var/cfengine/masterfiles/failsafe.cf#{cfagent_classes_args}") cfagent("-KI #{cfagent_classes_args}#{cfagent_extra_args}") end end # This handles verifying the CFEngine installation, installing it # if it was requested, and so on. This method will raise exceptions # if things are wrong. def handle_cfengine_installation if !@machine.guest.capability?(:cfengine_installed) @machine.ui.warn(I18n.t("vagrant.cfengine_cant_detect")) return end installed = @machine.guest.capability(:cfengine_installed) if !installed || @config.install == :force raise Vagrant::Errors::CFEngineNotInstalled if !@config.install @machine.ui.info(I18n.t("vagrant.cfengine_installing")) @machine.guest.capability(:cfengine_install, @config) if !@machine.guest.capability(:cfengine_installed) raise Vagrant::Errors::CFEngineInstallFailed end end end # This installs a set of files into the CFEngine folder within # the machine. # # @param [Pathname] local_path def install_files(local_path) @logger.debug("Copying local files to CFEngine: #{local_path}") @machine.communicate.sudo("rm -rf /tmp/cfengine-files") @machine.communicate.upload(local_path.to_s, "/tmp/cfengine-files") @machine.communicate.sudo("cp -R /tmp/cfengine-files/* /var/cfengine") end end end end