Fixes #9840: Introduce `ruby` option for trigger

This commit introduces a new option to the core trigger feature: `ruby`.
It can be defined to run ruby code when the trigger is configured to
fire. If you give the ruby block an env and machine argument, the
defined ruby code can use those variables internally.
This commit is contained in:
Brian Cain 2018-10-04 16:24:28 -07:00
parent c6a0793cc3
commit f4d618eb58
No known key found for this signature in database
GPG Key ID: 9FC4639B2E4510A0
7 changed files with 126 additions and 3 deletions

View File

@ -135,6 +135,10 @@ module Vagrant
if trigger.run_remote if trigger.run_remote
run_remote(trigger.run_remote, trigger.on_error, trigger.exit_codes) run_remote(trigger.run_remote, trigger.on_error, trigger.exit_codes)
end end
if trigger.ruby_block
execute_ruby(trigger.ruby_block)
end
end end
end end
@ -253,6 +257,13 @@ module Vagrant
@machine.ui.warn(I18n.t("vagrant.trigger.abort")) @machine.ui.warn(I18n.t("vagrant.trigger.abort"))
exit(exit_code) exit(exit_code)
end end
# Calls the given ruby block for execution
#
# @param [Proc] ruby_block
def execute_ruby(ruby_block)
ruby_block.call(@env, @machine)
end
end end
end end
end end

View File

@ -78,6 +78,17 @@ module VagrantPlugins
# @return [Integer] # @return [Integer]
attr_accessor :abort attr_accessor :abort
# Internal reader for the internal variable ruby_block
#
# @return [Proc]
attr_reader :ruby_block
# Variable used to store ruby proc when defining a ruby trigger
# with the "hash" syntax
#
# @return [Proc]
attr_accessor :ruby
def initialize(command) def initialize(command)
@logger = Log4r::Logger.new("vagrant::config::vm::trigger::config") @logger = Log4r::Logger.new("vagrant::config::vm::trigger::config")
@ -91,14 +102,26 @@ module VagrantPlugins
@run_remote = UNSET_VALUE @run_remote = UNSET_VALUE
@exit_codes = UNSET_VALUE @exit_codes = UNSET_VALUE
@abort = UNSET_VALUE @abort = UNSET_VALUE
@ruby = UNSET_VALUE
# Internal options # Internal options
@id = SecureRandom.uuid @id = SecureRandom.uuid
@command = command.to_sym @command = command.to_sym
@ruby_block = UNSET_VALUE
@logger.debug("Trigger defined for command: #{command}") @logger.debug("Trigger defined for command: #{command}")
end end
# Config option `ruby` for a trigger which reads in a ruby block and sets
# it to be evaluated when the configured trigger fires. This method is only
# invoked when the regular "block" syntax is used. Otherwise the proc is
# set through the attr_accessor if the hash syntax is used.
#
# @param [Proc] block
def ruby(&block)
@ruby_block = block
end
def finalize! def finalize!
# Ensure all config options are set to nil or default value if untouched # Ensure all config options are set to nil or default value if untouched
# by user # by user
@ -113,7 +136,11 @@ module VagrantPlugins
@exit_codes = DEFAULT_EXIT_CODE if @exit_codes == UNSET_VALUE @exit_codes = DEFAULT_EXIT_CODE if @exit_codes == UNSET_VALUE
@abort = nil if @abort == UNSET_VALUE @abort = nil if @abort == UNSET_VALUE
# these values are expected to always be an Array internally, @ruby_block = nil if @ruby_block == UNSET_VALUE
@ruby = nil if @ruby == UNSET_VALUE
@ruby_block = @ruby if @ruby
# These values are expected to always be an Array internally,
# but can be set as a single String or Symbol # but can be set as a single String or Symbol
# #
# Guests are stored internally as strings # Guests are stored internally as strings
@ -225,6 +252,10 @@ module VagrantPlugins
machine.ui.warn(I18n.t("vagrant.config.triggers.abort_false_type")) machine.ui.warn(I18n.t("vagrant.config.triggers.abort_false_type"))
end end
if @ruby_block && !ruby_block.is_a?(Proc)
errors << I18n.t("vagrant.config.triggers.ruby_bad_type", cmd: @command)
end
errors errors
end end

View File

@ -1781,6 +1781,9 @@ en:
only be a single integer or an array of integers. only be a single integer or an array of integers.
only_on_bad_type: |- only_on_bad_type: |-
Invalid type found for `only_on`. All values must be a `String` or `Regexp`. Invalid type found for `only_on`. All values must be a `String` or `Regexp`.
ruby_bad_type: |-
Invalid type for `ruby` option on trigger for command '%{cmd}'. Only `proc`
types are allowed.
privileged_ignored: |- privileged_ignored: |-
The `privileged` setting for option `run` for trigger command '%{command}' will be ignored and set to false. The `privileged` setting for option `run` for trigger command '%{command}' will be ignored and set to false.
powershell_args_ignored: |- powershell_args_ignored: |-

View File

@ -37,6 +37,10 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do
subject.warn = "Warning!!" subject.warn = "Warning!!"
subject.ignore = :up subject.ignore = :up
subject.only_on = "guest" subject.only_on = "guest"
subject.ruby do |env,machine|
var = 'test'
math = 1+1
end
subject.run = {inline: "apt-get update"} subject.run = {inline: "apt-get update"}
subject.run_remote = {inline: "apt-get update", env: {"VAR"=>"VAL"}} subject.run_remote = {inline: "apt-get update", env: {"VAR"=>"VAL"}}
end end
@ -67,6 +71,9 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do
cfg.only_on = :guest cfg.only_on = :guest
cfg.ignore = "up" cfg.ignore = "up"
cfg.abort = true cfg.abort = true
cfg.ruby do
var = 1+1
end
arr_cfg.only_on = ["guest", /other/] arr_cfg.only_on = ["guest", /other/]
arr_cfg.ignore = ["up", "destroy"] arr_cfg.ignore = ["up", "destroy"]
end end
@ -95,6 +102,11 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do
end end
end end
it "ensures ruby is a proc" do
cfg.finalize!
expect(cfg.ruby_block).to be_a(Proc)
end
it "converts aborts true to exit code 0" do it "converts aborts true to exit code 0" do
cfg.finalize! cfg.finalize!
@ -113,6 +125,7 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do
cfg.ignore = :up cfg.ignore = :up
cfg.abort = 3 cfg.abort = 3
cfg.only_on = "guest" cfg.only_on = "guest"
cfg.ruby = proc{ var = 1+1 }
cfg.run = {inline: "apt-get update"} cfg.run = {inline: "apt-get update"}
cfg.run_remote = {inline: "apt-get update", env: {"VAR"=>"VAL"}} cfg.run_remote = {inline: "apt-get update", env: {"VAR"=>"VAL"}}
end end
@ -127,7 +140,7 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do
expect(cfg.run).to be_a(VagrantPlugins::Shell::Config) expect(cfg.run).to be_a(VagrantPlugins::Shell::Config)
expect(cfg.run_remote).to be_a(VagrantPlugins::Shell::Config) expect(cfg.run_remote).to be_a(VagrantPlugins::Shell::Config)
expect(cfg.abort).to eq(3) expect(cfg.abort).to eq(3)
expect(cfg.ruby_block).to be_a(Proc)
end end
end end
end end

View File

@ -375,7 +375,6 @@ describe Vagrant::Plugin::V2::Trigger do
end end
context "#trigger_abort" do context "#trigger_abort" do
it "system exits when called" do it "system exits when called" do
output = "" output = ""
allow(machine.ui).to receive(:warn) do |data| allow(machine.ui).to receive(:warn) do |data|
@ -385,4 +384,20 @@ describe Vagrant::Plugin::V2::Trigger do
expect { subject.send(:trigger_abort, 3) }.to raise_error(SystemExit) expect { subject.send(:trigger_abort, 3) }.to raise_error(SystemExit)
end end
end end
context "#ruby" do
let(:trigger_run) { VagrantPlugins::Kernel_V2::TriggerConfig.new }
let(:block) { proc{var = 1+1} }
let(:ruby_trigger) { {info: "hi", ruby: block} }
before do
trigger_run.after(:up, ruby_trigger)
trigger_run.finalize!
end
it "executes a ruby block" do
expect(block).to receive(:call)
subject.send(:execute_ruby, block)
end
end
end end

View File

@ -34,6 +34,18 @@ The trigger class takes various options.
* `only_on` (string, regex, array) - Limit the trigger to these guests. Values can be a string or regex that matches a guest name. * `only_on` (string, regex, array) - Limit the trigger to these guests. Values can be a string or regex that matches a guest name.
* `ruby` (block) - A block of Ruby code to be executed. Can only be a `Proc` type. Two optional arguments may be passed into the given block: `env` and `machine`. These options correspond to the environment used, and the machine that the trigger is firing on. If no options are provided to the block, then they will not be available to be used with your Ruby code.
```ruby
ubuntu.trigger.after :up do |trigger|
trigger.info = "More information"
trigger.ruby do |env,machine|
greetings = "hello there #{machine.id}!"
puts greetings
end
end
```
* `run_remote` (hash) - A collection of settings to run a inline or remote script with on the guest. These settings correspond to the [shell provisioner](/docs/provisioning/shell.html). * `run_remote` (hash) - A collection of settings to run a inline or remote script with on the guest. These settings correspond to the [shell provisioner](/docs/provisioning/shell.html).
* `run` (hash) - A collection of settings to run a inline or remote script on the host. These settings correspond to the [shell provisioner](/docs/provisioning/shell.html). However, at the moment the only settings `run` takes advantage of are: * `run` (hash) - A collection of settings to run a inline or remote script on the host. These settings correspond to the [shell provisioner](/docs/provisioning/shell.html). However, at the moment the only settings `run` takes advantage of are:

View File

@ -93,3 +93,41 @@ end
Running `vagrant up` would fire the before trigger to start tinyproxy, where as Running `vagrant up` would fire the before trigger to start tinyproxy, where as
running either `vagrant destroy` or `vagrant halt` would stop tinyproxy. running either `vagrant destroy` or `vagrant halt` would stop tinyproxy.
### Ruby Option
Triggers can also be defined to run Ruby, rather than bash or powershell. An
example of this might be using a Ruby option to get more information from the `VBoxManage`
tool. In this case, we are printing the `ostype` defined for thte guest after
it has been brought up.
```ruby
Vagrant.configure("2") do |config|
config.vm.define "ubuntu" do |ubuntu|
ubuntu.vm.box = "ubuntu"
ubuntu.trigger.after :up do |trigger|
trigger.info = "More information with ruby magic"
trigger.ruby do |env,machine|
puts `VBoxManage showvminfo #{machine.id} --machinereadable | grep ostype`
end
end
end
end
```
If you are defining your triggers using the hash syntax, you must use the `Proc`
type for defining a ruby trigger.
```ruby
Vagrant.configure("2") do |config|
config.vm.define "ubuntu" do |ubuntu|
ubuntu.vm.box = "ubuntu"
ubuntu.trigger.after :up,
info: "More information with ruby magic",
ruby: proc{|env,machine| puts `VBoxManage showvminfo #{machine.id} --machinereadable | grep ostype`}
end
end
```