12

I am using Vagrant to deploy VMs for development. One of the requirements is that vagrant provision creates a new user (done in a provisioning script I wrote) and then vagrant ssh connects to the box as that user.

I cannot figure out how to tell if the box has been provisioned or not.

I see that the Vagrant provisioning code sets env[:provision_enabled] if this run is supposed to be doing provisioning, so I thought I would be able to do something like this:

if env[:provision_enabled]
  config.ssh.username = "#{data['ssh']['provision_username']}"
else
  config.ssh.username = "#{data['ssh']['username']}"
end

The idea is that SSH connections for provisioning would use one connection and SSH connections for everything else would use the other.

However, env[:provision_enabled] does not appear to be accessible in the Vagrantfile.

Is there a way to do this?

Moshe Katz
  • 15,992
  • 7
  • 69
  • 116
  • Why would you want to do this? The provisioning is always done as root afaik. Also, Vagrant will know if it's been provisioned or not on `vagrant up` – Jahaja Jul 21 '14 at 02:39
  • @Jahaja It is not correct that provisioning is always done as root. If `config.ssh.username` is set, provisioning is done as that user. I want to keep provisioning as the `vagrant` or the `root` user, but then switch to a user that was created during provisioning for all future SSH access. – Moshe Katz Jul 21 '14 at 02:56
  • I haven't yet had the need to change the username of ssh so you might be right. However the docs states that for SSH the default is to run as a privileged user. `privileged (boolean) - Specifies whether to execute the shell script as a privileged user or not (sudo). By default this is "true".` So I guess you want to switch to an unprivileged user beyond provisioning? – Jahaja Jul 21 '14 at 03:04
  • 1
    @Jahaja The important point is this: I want to switch to a user **that did not exist yet on the VM** when the provisioning was started. – Moshe Katz Jul 21 '14 at 03:11
  • `env[:provision_enabled]` is not accesible because the Vagrantfile is parsed before the environment is created. This information is available to provisioners and plugins, but not the Vagrantfile itself because of the load ordering. (see [Vagrant issue #7043](https://github.com/mitchellh/vagrant/issues/7043)) – spoorcc Aug 10 '17 at 12:36

4 Answers4

18

So for those who's looking for ready to use Vagrantfile code instructions, here is a function which checks if VM was provisioned and usage example:

# Function to check whether VM was already provisioned
def provisioned?(vm_name='default', provider='virtualbox')
  File.exist?(".vagrant/machines/#{vm_name}/#{provider}/action_provision")
end

Vagrant.configure("2") do |config|
  # do something special if VM was provisioned
  config.ssh.username = 'custom_username' if provisioned?

  [...]
end

Warning! It's hackery method with checking action_provision file existence. But it works and at the moment of posting, there are no other good ways.

Eugen
  • 1,465
  • 1
  • 13
  • 17
9

This seems to be determined by the action_provision file in the Vagrant data dir (.vagrant/). It's usually located in the same folder as your Vagrantfile.

So a crude workaround would be to set the ssh username in your Vagrantfile depending on if the file exists or not. I haven't been able to test this though, but if you just rename or remove the action_provision file and go vagrant reload it should provision again.

Jahaja
  • 3,222
  • 1
  • 20
  • 11
  • This is close enough to what I ended up trying to do. (However, in the end, I decided to build a custom BOX file that already has the user instead of trying to create the user while provisioning.) – Moshe Katz Jul 25 '14 at 04:14
  • 1
    Great, I recommend taking a look at http://packer.io for automating the building of vagrant boxes. – Jahaja Jul 25 '14 at 09:48
  • 1
    That's exactly what I'm using. – Moshe Katz Jul 25 '14 at 12:18
3

EDIT

Was too fast to answer without trying it out first. The code in the link below may have worked in previous versions, however in 1.7.2 it will not work; You need to tweak it a bit:

Vagrant.configure("2") do |config|
  if ARGV[0] == "ssh"
      config.ssh.username = 'other_username'
  end

  ...
end

original answer below

Came here looking for an answer to the same question but none of existing ones were quite satisfying, so with a bit more digging I found this comment on github about how you could go around for your requirements:

Vagrant.configure("2") do |config|
  if VAGRANT_COMMAND == "ssh"
      config.ssh.username = 'other_username'
  end

  ...
end

You just check if the vagrant command you're issuing is ssh then it will use the username you specified.

Sakis Vtdk
  • 489
  • 6
  • 12
2

I can't find a straightforward way of doing this. Sounds like the simplest solution would be to check the provision result i.e. can you log in with user created after provisioning?

Another option would be to always run vagrant reload --provision to ensure the box is in a provisioned state before continuing.

Andy
  • 173
  • 1
  • 6
  • Running `vagrant reload --provision` wouldn't help because I need to set in the `Vagrantfile` which user should be used to login in order to do the provisioning in the first place. – Moshe Katz Jul 20 '14 at 23:53
  • Is something like: `ssh -q "#{data['ssh']['username']}@host exit; if $? == 0; then echo 'Is provisioned'; else echo 'Needs provisioned'`; fi` possible in your situation? This will test if an ssh connection is possible with the user created during provisioning, implying that if successful the provision has taken place. – Andy Jul 20 '14 at 23:59