211 lines
7.0 KiB
Ruby
211 lines
7.0 KiB
Ruby
require 'log4r'
|
|
require 'shellwords'
|
|
require 'fileutils'
|
|
|
|
require "vagrant/util/subprocess"
|
|
|
|
#require 'pry'
|
|
|
|
module Vagrant
|
|
module Plugin
|
|
module V2
|
|
class Trigger
|
|
# @return [Kernel_V2/Config/Trigger]
|
|
attr_reader :config
|
|
|
|
# This class is responsible for setting up basic triggers that were
|
|
# defined inside a Vagrantfile.
|
|
#
|
|
# @param [Object] env Vagrant environment
|
|
# @param [Object] config Trigger configuration
|
|
# @param [Object] machine Active Machine
|
|
def initialize(env, config, machine)
|
|
@env = env
|
|
@config = config
|
|
@machine = machine
|
|
|
|
@logger = Log4r::Logger.new("vagrant::trigger::#{self.class.to_s.downcase}")
|
|
end
|
|
|
|
# Fires all triggers, if any are defined for the action and guest
|
|
#
|
|
# @param [Symbol] action Vagrant command to fire trigger on
|
|
# @param [Symbol] stage :before or :after
|
|
# @param [String] guest_name The guest that invoked firing the triggers
|
|
def fire_triggers(action, stage, guest_name)
|
|
# get all triggers matching action
|
|
triggers = []
|
|
if stage == :before
|
|
triggers = config.before_triggers.select { |t| t.command == action }
|
|
elsif stage == :after
|
|
triggers = config.after_triggers.select { |t| t.command == action }
|
|
else
|
|
# raise error, stage was not given
|
|
# This is an internal error
|
|
# TODO: Make sure this error exist
|
|
raise Errors::Triggers::NoStageGiven,
|
|
action: action,
|
|
stage: stage,
|
|
guest_name: guest_name
|
|
end
|
|
|
|
triggers = filter_triggers(triggers, guest_name)
|
|
|
|
unless triggers.empty?
|
|
@logger.info("Firing trigger for action #{action} on guest #{guest_name}")
|
|
# TODO I18N me
|
|
@machine.ui.info("Running triggers #{stage} #{action}...")
|
|
fire(triggers, guest_name)
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
#-------------------------------------------------------------------
|
|
# Internal methods, don't call these.
|
|
#-------------------------------------------------------------------
|
|
|
|
# Filters triggers to be fired based on configured restraints
|
|
#
|
|
# @param [Array] triggers An array of triggers to be filtered
|
|
# @param [String] guest_name The name of the current guest
|
|
# @return [Array] The filtered array of triggers
|
|
def filter_triggers(triggers, guest_name)
|
|
# look for only_on trigger constraint and if it doesn't match guest
|
|
# name, throw it away also be sure to preserve order
|
|
filter = triggers.dup
|
|
|
|
filter.each do |trigger|
|
|
index = nil
|
|
if !trigger.only_on.nil?
|
|
trigger.only_on.each do |o|
|
|
if o.match?(guest_name)
|
|
index = triggers.index(trigger)
|
|
end
|
|
end
|
|
end
|
|
|
|
if !index.nil?
|
|
@logger.debug("Trigger #{trigger.id} will be ignored for #{guest_name}")
|
|
triggers.delete_at(index)
|
|
end
|
|
end
|
|
|
|
return triggers
|
|
end
|
|
|
|
# Fires off all triggers in the given array
|
|
#
|
|
# @param [Array] triggers An array of triggers to be fired
|
|
def fire(triggers, guest_name)
|
|
# ensure on_error is respected by exiting or continuing
|
|
|
|
triggers.each do |trigger|
|
|
@logger.debug("Running trigger #{trigger.id}...")
|
|
|
|
# TODO: I18n me
|
|
if !trigger.name.nil?
|
|
@machine.ui.info("Running trigger: #{trigger.name}...")
|
|
else
|
|
@machine.ui.info("Running trigger...")
|
|
end
|
|
|
|
if !trigger.info.nil?
|
|
@logger.debug("Executing trigger info message...")
|
|
self.info(trigger.info)
|
|
end
|
|
|
|
if !trigger.warn.nil?
|
|
@logger.debug("Executing trigger warn message...")
|
|
self.warn(trigger.warn)
|
|
end
|
|
|
|
if !trigger.run.nil?
|
|
@logger.debug("Executing trigger run script...")
|
|
self.run(trigger.run, trigger.on_error)
|
|
end
|
|
|
|
if !trigger.run_remote.nil?
|
|
@logger.debug("Executing trigger run_remote script on #{guest_name}...")
|
|
self.run_remote(trigger.run, trigger.on_error)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Prints the given message at info level for a trigger
|
|
#
|
|
# @param [String] message The string to be printed
|
|
def info(message)
|
|
@machine.ui.info(message)
|
|
end
|
|
|
|
# Prints the given message at warn level for a trigger
|
|
#
|
|
# @param [String] message The string to be printed
|
|
def warn(message)
|
|
@machine.ui.warn(message)
|
|
end
|
|
|
|
# Runs a script on a guest
|
|
#
|
|
# @param [ShellProvisioner/Config] config A Shell provisioner config
|
|
def run(config, on_error)
|
|
# TODO: I18n me
|
|
if !config.inline.nil?
|
|
cmd = Shellwords.split(config.inline)
|
|
@machine.ui.info("Executing local: Inline script")
|
|
else
|
|
cmd = File.expand_path(config.path, @env.root_path)
|
|
FileUtils.chmod("+x", cmd) # TODO: what about windows
|
|
@machine.ui.info("Executing local: File script #{config.path}")
|
|
end
|
|
|
|
begin
|
|
# TODO: should we check config or command for sudo? And if so, WARN the user?
|
|
result = Vagrant::Util::Subprocess.execute(*cmd, :notify => [:stdout, :stderr]) do |type,data|
|
|
case type
|
|
when :stdout
|
|
@machine.ui.detail(data)
|
|
when :stderr
|
|
@machine.ui.error(data)
|
|
end
|
|
end
|
|
|
|
rescue Exception => e
|
|
if on_error == :halt
|
|
@logger.debug("Trigger run encountered an error. Halting on error...")
|
|
raise e
|
|
else
|
|
@logger.debug("Trigger run encountered an error. Continuing on anyway...")
|
|
# TODO: I18n me and write better message
|
|
@machine.ui.error("Trigger run failed:")
|
|
@machine.ui.error(e.message)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Runs a script on the host
|
|
#
|
|
# @param [ShellProvisioner/Config] config A Shell provisioner config
|
|
def run_remote(config, on_error)
|
|
# make sure guest actually exists, if not, display a WARNING
|
|
#
|
|
# get machine, and run shell provisioner on it
|
|
begin
|
|
rescue Exception => e
|
|
if on_error == :halt
|
|
@logger.debug("Trigger run encountered an error. Halting on error...")
|
|
raise e
|
|
else
|
|
@logger.debug("Trigger run encountered an error. Continuing on anyway...")
|
|
# TODO: I18n me and write better message
|
|
@machine.ui.error("Trigger run failed:")
|
|
@machine.ui.error(e.message)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|