vagrant
vagrant copied to clipboard
`machine_action_provision` hook and `Vagrant::Action::Builtin::Provision` action `after` Triggers run before provisioning
TLDR: machine_action_provision after hook and Vagrant::Action::Builtin::Provision after action triggers run before provisioning (but provisioner_run hook works as intended).
Note: I apologize if this is actually two issues... I did some code diving and I think it might be the same issue. I suspect a missing lock or the provisioning process being spawned incorrectly. I'd be more than interested in helping get the PR up for it, but I need someone who is familiar with the code base to confirm the issue and the location.
Debug output
-
-
-
grep "TRIGGER\|PROVISIONER\|Calling.*Provision" vagrant-up-debug.log -
grep "Trigger defined\|TRIGGER\|PROVISIONER\|Calling.*Provision\|machine_action_provision" vagrant-provision-debug.log
Expected behavior
vagrant up should execute triggers/provisioning in the following order:
- Before action trigger for
Vagrant::Action::Builtin::Provision - Provisioners
- After action trigger for
Vagrant::Action::Builtin::Provision
vagrant provision should execute triggers/provisioning in the following order:
- Before hook trigger for
machine_actiton_provision - Before action trigger for
Vagrant::Action::Builtin::Provision - Provisioners
- After action trigger for
Vagrant::Action::Builtin::Provision - After hook trigger for
machine_actiton_provision
Actual behavior
vagrant up executes before AND after triggers before provisioning:
- Before action trigger for
Vagrant::Action::Builtin::Provision - After action trigger for
Vagrant::Action::Builtin::Provision - Provisioners
vagrant provision executes before AND after triggers before provisioning:
- Before hook trigger for
machine_actiton_provision - Before action trigger for
Vagrant::Action::Builtin::Provision - After action trigger for
Vagrant::Action::Builtin::Provision - After hook trigger for
machine_actiton_provision - Provisioners
Reproduction information
Vagrant version
$ vagrant version
Installed Version: 2.4.1
Latest Version: 2.4.1
You're running an up-to-date version of Vagrant!
Host operating system
EndeavourOS (rolling, up to date)
Guest operating system
debian/bookworm64
Steps to reproduce
- Copy/paste the below Vagrantfile locally
- Execute
vagrant up(Replicates: AfterVagrant::Action::Builtin::Provisionaction trigger issue) - Execute
vagrant provision(Replicates: Aftermachine_action_provisionhook andVagrant::Action::Builtin::Provisionaction trigger issue)
Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "debian/bookworm64"
config.vm.synced_folder ".", "/vagrant", disabled: true
# Provisioners:
config.vm.provision "PROVISIONER 1", type: :shell, inline: "echo EXECUTING PROVISIONER 1"
config.vm.provision "PROVISIONER 2", type: :shell, inline: "echo EXECUTING PROVISIONER 2"
# Triggers:
# WORKS AS EXPECTED (Executes immediately after the COMMAND provision starts, but before
# performing any provisioning actions)
config.trigger.before :machine_action_provision, type: :hook,
name: "HOOK TRIGGER BEFORE machine_action_provision",
info: "INSIDE BEFORE machine_action_provision HOOK TRIGGER"
# WORKS AS EXPECTED (Executes after machine_action_provision, and before "Calling IN action: Provision")
config.trigger.before Vagrant::Action::Builtin::Provision, type: :action,
name: "ACTION TRIGGER BEFORE Vagrant::Action::Builtin::Provision",
info: "INSIDE BEFORE Vagrant::Action::Builtin::Provision TRIGGER"
# UNEXPECTED: Executes **immediately after** "Calling IN action: Provision", BEFORE any
# provisioning is done.
# EXPECTED: Executes immediately before/after "Calling OUT action: Provision"
config.trigger.after Vagrant::Action::Builtin::Provision, type: :action,
name: "ACTION TRIGGER AFTER Vagrant::Action::Builtin::Provision",
info: "INSIDE AFTER Vagrant::Action::Builtin::Provision TRIGGER"
# UNEXPECTED: Executes immediately after the Provision action trigger, which is shortly
# after STARTING Provisioning, but BEFORE any provisioning is done.
# EXPECTED: executes after finishing provisioning.
config.trigger.after :machine_action_provision, type: :hook,
name: "HOOK TRIGGER AFTER machine_action_provision",
info: "INSIDE AFTER machine_action_provision HOOK TRIGGER"
# config.trigger.before :provisioner_run, type: :hook, name: "HOOK TRIGGER BEFORE provisioner_run", info: "Running before provisioner_run hook trigger" # WORKS AS EXPECTED (Executes before each Provisioner)
# config.trigger.after :provisioner_run, type: :hook, name: "HOOK TRIGGER AFTER provisioner_run", info: "Running after provisioner_run hook trigger" # WORKS AS EXPECTED (Executes after each Provisioner)
end
Hi! Thanks for the detailed report! I've been looking into this, and have some findings, but first: Is there a specific behavior you are looking for when using the action/hook above, that the provisioner_run isn't able to do?
I ask because the behavior you have outlined is unintuitive, but isn't incorrect based on how the Vagrant stack works. The stack is made up of middlewares, which tend to perform their operation and call to the next item, but in some cases will continue to do things once the next item completes. In the Provision action, the next item in the stack is executed here, but the actual provisioning happens at the end here, after the rest of the stack has executed and exited.
The defined triggers insert a new action into the stack prior to the stack being executed, so while its placement will be correct in the stack, where it is actually run may be different due to the individual behaviors of the actions in that stack (like you've observed).
Usually, trying to hook into the actions directly is used by plugins that need this functionality specifically. For most use-cases, using the provisioner_run hook is the right/most expected behavior. But if this is something that you need for a specific case, we'd be happy to help figure that out.
Hi @allisonlarson ,
Apologies on the super late reply. This was so long ago, I had to try to figure out what the use case I abandoned was. I think it boiled down to the following:
- Intuitiveness. IMHO, anything that is named
afterand*provision*would occur "after provisioning." I'm admittedly somewhat new to the vagrant ecosystem, and I have never done any plugin dev, and I am not intimate with the middlewares. So while I am a dev, this is strictly from a user perspective. I can definitely understand how people who have been working with this for a long time might have gotten used to it, or it makes sense when you get really in the weeds. I also recognize that, if this was by design, changing it would break many worlds. It appears I might have made an incorrect assumption in believing this was a bug. - Ability to perform an action after provisioning. My specific use case was to write a hook to snapshot the VM immediately after it was provisioned so that I had a clean provisioned snapshot to roll back to during the development lifecycle. I generally use vagrant in dev environments and I have a tendency to forget to snapshot it after I provision and then I need to go thru an often lengthy destroy/recreate process. I could see this being a specific feature request (like a flag on
vagrant provisionand maybe alsovagrant up). But I do still stand by bullet 1 in that the "afters" seem unintuitive to a user, so maybe enhance docs at least?