Vagrant execute script or command after every guest restart (vagrant up)
Asked Answered
O

4

40

I know about the provisioning script, but this is a different script that I am asking about. I want a script to be executed after every restart of the guest.

I am using shell provisioner.

config.vm.provision :shell, path: "vagrant/bootstrap.sh"

I can't put my commands in this script that I want to run after every restart.

Basically, I want one of my applications to be started when user executes vagrant up.

My guest is ubuntu 14.04 trusty and one solution I found was to do following on my guest -

sudo crontab -e
#add the following line 
@reboot sh /path/to/my_script_on_guest.sh

I can try to do this in my provisioning script, but sudo crontab -e asks for an editor and I have to kind of interactively add the line. Since the crontab file is not fixed I don't know if it is feasible to do one liner file edits like

echo '@reboot sh /path/to/my_script_on_guest.sh' >> crontab_file

I am guessing that this must be a guest OS specific thing.

Is this possible to achieve using Vagrant?

EDIT: corrected from ssh provisioner to shell provisioner.

Ovular answered 13/5, 2016 at 10:59 Comment(0)
E
69

you can use run: 'always'

config.vm.provision :shell, path: "vagrant/bootstrap.sh", run: 'always'

This will make sure your command are executed every time your VM is starting (vagrant up or vagrant reload)

If you need only certain commands to be always run, you can split your script

config.vm.provision :shell, path: "vagrant/bootstrap1.sh"
config.vm.provision :shell, path: "vagrant/bootstrap2.sh", run: 'always'
config.vm.provision :shell, path: "vagrant/bootstrap3.sh"

script will be run in order, bootstrap1 then 2 then 3 when the machine is first provisioned

any further time you run vagrant up (or reload) only bootstrap2 will be run

Eraser answered 13/5, 2016 at 11:16 Comment(3)
Thanks. But I have other provisioning steps in my bootstrap.sh which are not idempotent. Is there any other lifecycle hook?Ovular
yes clear, so split your script and make the things indempotent in another script and do not run always - scripts are run in orderEraser
Perfect! This is exactly what I needed.Rodin
H
5

Just offering an alternative here that worked for me, using vagrant triggers. Consider this example straight from their docs:

Running a remote script to save a database on your host before destroying a guest:

Vagrant.configure("2") do |config|   
  config.vm.define "ubuntu" do |ubuntu|
    ubuntu.vm.box = "ubuntu"

    ubuntu.trigger.before :destroy do |trigger|
      trigger.warn = "Dumping database to /vagrant/outfile"
      trigger.run_remote = {inline: "pg_dump dbname > /vagrant/outfile"} 

      # or trigger.run = {...} to run the command on the host instead 
      # of guest
    end
  end 
end

There's also the related vagrant-triggers plugin you can check out

Hampshire answered 22/6, 2018 at 13:38 Comment(1)
Works! I use this: config.trigger.after :reload, :up do |trigger|Briquette
E
1

I used ubuntu 18.04. Triggers didnt work for me so i chose to copy post-provision script to vm box and then from a master script execute the desired post-provision:

config.trigger.before :provisioner_run, type: :hook do |t|
    t.info = "Before the provision!"
  end

  config.vm.provision "shell" do |s|
    s.inline = "echo $1  "
    s.args   = [" '--->' Provisioning the environment!"]
  end 
  config.vm.provision "file", source: "scripts/post-provision/.", destination: "/home/vagrant"
  config.vm.provision "shell", path: "scripts/install.sh"
  # config.vm.provision "shell", path: "scripts/bootstrap.sh", run: 'always'

  # config.trigger.after :up do |trigger|
  #   trigger.info = "Installing Monitoring Stack..."
  #   trigger.run_remote = {path: "./install-monitor-stack.sh"}
  # end
end

master script contents uses exec to refresh new shell. You could also use

reset

sudo chmod  +x *.sh
exec /home/vagrant/install-monitor-stack.sh
exec /home/vagrant/bootstrap.sh
Eichmann answered 17/7, 2019 at 5:12 Comment(0)
G
0

I have 2 sections of provisioning shell. One regular and one with run: always param. This works fine for me. In my example it starts nginx on my vagrant image. I've added run param before inline . When placed at the end (after SHELL) , it doesn't work.

config.vm.provision "shell", run: "always", inline: <<-SHELL
    sudo systemctl start nginx
SHELL
Gunsel answered 29/9, 2022 at 16:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.