-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate vagrant-triggers plugin functionality into core Vagrant #9713
Merged
briancain
merged 95 commits into
hashicorp:master
from
briancain:vagrant-triggers-config
Apr 24, 2018
Merged
Changes from 92 commits
Commits
Show all changes
95 commits
Select commit
Hold shift + click to select a range
a194057
Add trigger config plugin
briancain 813ffd0
Add more trigger config options
briancain 0142722
Add run and run_remote scaffolding
briancain 01b9040
Use proper command reference for command whitelist params
briancain 7cccddc
Add basic scaffolding for command parsing
briancain bb2f3b3
Add basic unit test
briancain fdf1b58
Introduce ids for trigger blocks
briancain 6f00eb5
Move trigger options into own plugin class
briancain e0a5b1d
Parse block trigger configs
briancain c10ae07
Store correct command for trigger
briancain 50ecf45
Add more doc to create_trigger function
briancain 3c5e4b2
Fix variable doc
briancain 375e8d7
Remove old comments
briancain 8e72ae5
Add basic validation for trigger config objects
briancain 60ff248
Display warning if vagrant command for trigger is not found
briancain a96baad
Add comments for later dev
briancain b04f136
Move warning to logger rather than guest
briancain 5ca1d1a
Finalize config in plugins finalize, improve docs
briancain d26a925
Update variable doc
briancain 607368a
Introduce merge function to preserve internal state
briancain 0cbf697
Update config class setting
briancain 51e4118
Debug commit
briancain f0ec7c7
Potential solution for trigger validation when guest is defined
briancain 1591ae9
Make run and run_remote settings shell provisioner configs
briancain d3dde73
Update trigger code docs
briancain e752878
Update finalize method for run and run_remote objects
briancain 60c4ffa
Ensure run & run_remote are Hashes before updating to shell config
briancain d0d69e5
Update return doc string on validate
briancain 42419bb
Fix rspec tests
briancain 3dec686
Update trigger unit tests
briancain 6cbb5d8
Add unit tests for config, fix type change bug with map!
briancain abb6d77
Move location of command validator
briancain 7b1b044
Check for default on_error behavior setting
briancain e157362
Add run and run_remote expectations
briancain fc526a1
Add basic create_trigger rspec test
briancain 7dae1ac
Add some "default" options to be validated
briancain 956ed00
Update trigger config merge function
briancain e7274f1
Improve config rspec tests
briancain a5d8cc1
Update trigger classes with comments
briancain 4ecf682
Add basic trigger plugin scaffold
briancain 372a6a7
Initial trigger plugin scaffolding
briancain 1462b3f
Simplify trigger command filtering
briancain 0e5cd90
Add missing param
briancain 76418b9
Simplify trigger selection
briancain 6373441
Ensure guest name is a string
briancain 09bb986
Add basic website pages for triggers
briancain eac2fcf
Filter triggers based on only_on restraint
briancain bbf4e3c
Reduce fire trigger methods to a single method
briancain 93af398
Update params for NoStageGiven error
briancain 48b7c68
Use active machine object
briancain 616b0f9
Preserve returning environment after machine action gets called
briancain 0953287
Relax only_on rspec tests
briancain fbad4c7
Add basic spec test for trigger class
briancain d750169
Add some logging around run and run_remote
briancain 975b8e7
Get basic run triggers executing inline scripts
briancain 59965f4
Properly filter triggers
briancain 8b70abd
Send the correct config message to warn
briancain e078767
run now supports script files as well as inline scripts
briancain fd28783
Move exception warnings in run function
briancain 2c30eab
Don't run local commands as sudo by default
briancain a4faaa1
Provision run_remote using the shell provisioner
briancain 8b71c24
Match properly on guests with trigger filtering
briancain a857056
Update color for run_remote to match shell provisioner colors
briancain a1e4fe4
Align how local provisioner looks with shell provisioner
briancain 600557f
Move strings to translation file
briancain 85dedf2
Ensure that :all triggers don't get filtered out
briancain 6ea7819
Update rspec tests for trigger plugin
briancain c832168
Update trigger config docs
briancain ca672eb
Trigger plugin cleanup
briancain 3ad4f57
Add only_on validation for config
briancain 693eb2f
Add machine level warning when privileged option is set for run
briancain 767a315
Trigger cleanup
briancain e7d07cb
Add rspec tests for trigger plugin
briancain 7cdb32f
Use inclunde? instead of any? for ruby 2.3
briancain a5fe84d
Fix string translation
briancain 6bf0196
Fix run command for windows hosts
briancain 0054c5a
Raise error if incomplete trigger block is defined
briancain 2dadc04
Fix trigger doc sidebar
briancain a204045
Add trigger documentation
briancain e0806f6
Remove TODO
briancain c35e0a4
Update docs with some basic trigger examples
briancain 8451cbf
Move up location of error message
briancain 4e5e4d0
Use args setting for run option in trigger
briancain 6f2b5a9
Update trigger docs
briancain 5e9387d
Add basic triggers example
briancain 12b1a3d
Update triggers based on code review
briancain 188fd5d
Split out run methods with Powershell functions
briancain e25cb51
Properly print warnings on config settings that aren't supported
briancain bd133e1
Docs updates for triggers
briancain 2000a11
Add tests for powershell run functions
briancain a1ca29c
Add warn and info validation translation strings
briancain daffd87
Use match over match? for Ruby 2.3
briancain 1eabd09
Website updates based on feedback
briancain a9be56b
Code updates based on PR feedback
briancain afc074f
Document valid trigger commands
briancain File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
require 'fileutils' | ||
require 'log4r' | ||
require 'shellwords' | ||
|
||
require Vagrant.source_root.join("plugins/provisioners/shell/provisioner") | ||
require "vagrant/util/subprocess" | ||
require "vagrant/util/platform" | ||
require "vagrant/util/powershell" | ||
|
||
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 do |t| | ||
t.command == action || (t.command == :all && !t.ignore.include?(action)) | ||
end | ||
elsif stage == :after | ||
triggers = config.after_triggers.select do |t| | ||
t.command == action || (t.command == :all && !t.ignore.include?(action)) | ||
end | ||
else | ||
raise Errors::TriggersNoStageGiven, | ||
action: action, | ||
stage: stage, | ||
guest_name: guest_name | ||
end | ||
|
||
triggers = filter_triggers(triggers, guest_name) | ||
|
||
if !triggers.empty? | ||
@logger.info("Firing trigger for action #{action} on guest #{guest_name}") | ||
@machine.ui.info(I18n.t("vagrant.trigger.start", stage: stage, action: 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 | ||
match = false | ||
if trigger.only_on | ||
trigger.only_on.each do |o| | ||
if o.match(guest_name) | ||
# trigger matches on current guest, so we're fine to use it | ||
match = true | ||
break | ||
end | ||
end | ||
# no matches found, so don't use trigger for guest | ||
index = triggers.index(trigger) unless match == true | ||
end | ||
|
||
if !index.nil? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
@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}...") | ||
|
||
if !trigger.name.nil? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
@machine.ui.info(I18n.t("vagrant.trigger.fire_with_name", | ||
name: trigger.name)) | ||
else | ||
@machine.ui.info(I18n.t("vagrant.trigger.fire")) | ||
end | ||
|
||
if trigger.info | ||
info(trigger.info) | ||
end | ||
|
||
if trigger.warn | ||
warn(trigger.warn) | ||
end | ||
|
||
if trigger.run | ||
run(trigger.run, trigger.on_error) | ||
end | ||
|
||
if trigger.run_remote | ||
run_remote(trigger.run_remote, 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 [Provisioners::Shell::Config] config A Shell provisioner config | ||
def run(config, on_error) | ||
if config.inline | ||
cmd = Shellwords.split(config.inline) | ||
|
||
@machine.ui.detail(I18n.t("vagrant.trigger.run.inline", command: config.inline)) | ||
else | ||
cmd = File.expand_path(config.path, @env.root_path) | ||
cmd << " #{config.args.join(' ' )}" if config.args | ||
cmd = Shellwords.split(cmd) | ||
|
||
@machine.ui.detail(I18n.t("vagrant.trigger.run.script", path: config.path)) | ||
end | ||
|
||
# Pick an execution method to run the script or inline string with | ||
# Default to Subprocess::Execute | ||
exec_method = Vagrant::Util::Subprocess.method(:execute) | ||
|
||
if Vagrant::Util::Platform.windows? | ||
if config.inline | ||
exec_method = Vagrant::Util::PowerShell.method(:execute_inline) | ||
else | ||
exec_method = Vagrant::Util::PowerShell.method(:execute) | ||
end | ||
end | ||
|
||
begin | ||
result = exec_method.call(*cmd, :notify => [:stdout, :stderr]) do |type,data| | ||
options = {} | ||
case type | ||
when :stdout | ||
options[:color] = :green if !config.keep_color | ||
when :stderr | ||
options[:color] = :red if !config.keep_color | ||
end | ||
|
||
@machine.ui.detail(data, options) | ||
end | ||
rescue => e | ||
@machine.ui.error(I18n.t("vagrant.errors.triggers_run_fail")) | ||
@machine.ui.error(e.message) | ||
|
||
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...") | ||
@machine.ui.warn(I18n.t("vagrant.trigger.on_error_continue")) | ||
end | ||
end | ||
end | ||
|
||
# Runs a script on the guest | ||
# | ||
# @param [ShellProvisioner/Config] config A Shell provisioner config | ||
def run_remote(config, on_error) | ||
unless @machine.state.id == :running | ||
if on_error == :halt | ||
raise Errors::TriggersGuestNotRunning, | ||
machine_name: @machine.name, | ||
state: @machine.state.id | ||
else | ||
@machine.ui.error(I18n.t("vagrant.errors.triggers_guest_not_running", | ||
machine_name: @machine.name, | ||
state: @machine.state.id)) | ||
@machine.ui.warn(I18n.t("vagrant.trigger.on_error_continue")) | ||
return | ||
end | ||
end | ||
|
||
prov = VagrantPlugins::Shell::Provisioner.new(@machine, config) | ||
|
||
begin | ||
prov.provision | ||
rescue => e | ||
@machine.ui.error(I18n.t("vagrant.errors.triggers_run_fail")) | ||
|
||
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...") | ||
@machine.ui.error(e.message) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be updated with actual types expected