diff --git a/lib/vagrant/plugin/v2/trigger.rb b/lib/vagrant/plugin/v2/trigger.rb index 73c9a7570..d9caf21ef 100644 --- a/lib/vagrant/plugin/v2/trigger.rb +++ b/lib/vagrant/plugin/v2/trigger.rb @@ -135,6 +135,10 @@ module Vagrant if trigger.run_remote run_remote(trigger.run_remote, trigger.on_error, trigger.exit_codes) end + + if trigger.ruby_block + execute_ruby(trigger.ruby_block) + end end end @@ -253,6 +257,13 @@ module Vagrant @machine.ui.warn(I18n.t("vagrant.trigger.abort")) exit(exit_code) 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 diff --git a/plugins/kernel_v2/config/vm_trigger.rb b/plugins/kernel_v2/config/vm_trigger.rb index ad856995a..aa27da955 100644 --- a/plugins/kernel_v2/config/vm_trigger.rb +++ b/plugins/kernel_v2/config/vm_trigger.rb @@ -78,6 +78,17 @@ module VagrantPlugins # @return [Integer] 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) @logger = Log4r::Logger.new("vagrant::config::vm::trigger::config") @@ -91,14 +102,26 @@ module VagrantPlugins @run_remote = UNSET_VALUE @exit_codes = UNSET_VALUE @abort = UNSET_VALUE + @ruby = UNSET_VALUE # Internal options @id = SecureRandom.uuid @command = command.to_sym + @ruby_block = UNSET_VALUE @logger.debug("Trigger defined for command: #{command}") 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! # Ensure all config options are set to nil or default value if untouched # by user @@ -113,7 +136,11 @@ module VagrantPlugins @exit_codes = DEFAULT_EXIT_CODE if @exit_codes == 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 # # Guests are stored internally as strings @@ -225,6 +252,10 @@ module VagrantPlugins machine.ui.warn(I18n.t("vagrant.config.triggers.abort_false_type")) end + if @ruby_block && !ruby_block.is_a?(Proc) + errors << I18n.t("vagrant.config.triggers.ruby_bad_type", cmd: @command) + end + errors end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 774f92887..530f8f5c3 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1781,6 +1781,9 @@ en: only be a single integer or an array of integers. only_on_bad_type: |- 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: |- The `privileged` setting for option `run` for trigger command '%{command}' will be ignored and set to false. powershell_args_ignored: |- diff --git a/test/unit/plugins/kernel_v2/config/vm_trigger_test.rb b/test/unit/plugins/kernel_v2/config/vm_trigger_test.rb index a4b28153f..e6d69384a 100644 --- a/test/unit/plugins/kernel_v2/config/vm_trigger_test.rb +++ b/test/unit/plugins/kernel_v2/config/vm_trigger_test.rb @@ -37,6 +37,10 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do subject.warn = "Warning!!" subject.ignore = :up subject.only_on = "guest" + subject.ruby do |env,machine| + var = 'test' + math = 1+1 + end subject.run = {inline: "apt-get update"} subject.run_remote = {inline: "apt-get update", env: {"VAR"=>"VAL"}} end @@ -67,6 +71,9 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do cfg.only_on = :guest cfg.ignore = "up" cfg.abort = true + cfg.ruby do + var = 1+1 + end arr_cfg.only_on = ["guest", /other/] arr_cfg.ignore = ["up", "destroy"] end @@ -95,6 +102,11 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do 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 cfg.finalize! @@ -113,6 +125,7 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do cfg.ignore = :up cfg.abort = 3 cfg.only_on = "guest" + cfg.ruby = proc{ var = 1+1 } cfg.run = {inline: "apt-get update"} cfg.run_remote = {inline: "apt-get update", env: {"VAR"=>"VAL"}} end @@ -127,7 +140,7 @@ describe VagrantPlugins::Kernel_V2::VagrantConfigTrigger do expect(cfg.run).to be_a(VagrantPlugins::Shell::Config) expect(cfg.run_remote).to be_a(VagrantPlugins::Shell::Config) expect(cfg.abort).to eq(3) + expect(cfg.ruby_block).to be_a(Proc) end end - end diff --git a/test/unit/vagrant/plugin/v2/trigger_test.rb b/test/unit/vagrant/plugin/v2/trigger_test.rb index e413fdb51..9b88b8d41 100644 --- a/test/unit/vagrant/plugin/v2/trigger_test.rb +++ b/test/unit/vagrant/plugin/v2/trigger_test.rb @@ -375,7 +375,6 @@ describe Vagrant::Plugin::V2::Trigger do end context "#trigger_abort" do - it "system exits when called" do output = "" 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) 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 diff --git a/website/source/docs/triggers/configuration.html.md b/website/source/docs/triggers/configuration.html.md index bd801869c..01d334c2e 100644 --- a/website/source/docs/triggers/configuration.html.md +++ b/website/source/docs/triggers/configuration.html.md @@ -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. +* `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` (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: diff --git a/website/source/docs/triggers/usage.html.md b/website/source/docs/triggers/usage.html.md index b53f21d16..a5ec536b8 100644 --- a/website/source/docs/triggers/usage.html.md +++ b/website/source/docs/triggers/usage.html.md @@ -93,3 +93,41 @@ end Running `vagrant up` would fire the before trigger to start tinyproxy, where as 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 +```