Vagrant: Vagrant.has_plugin?("vagrant-vbguest") always returns false after upgrade to 2.1.4

Created on 31 Aug 2018  ·  20Comments  ·  Source: hashicorp/vagrant

I upgraded from 2.1.2 to 2.1.4 this morning, and now the plugin test for the VB Guest plugin always returns false.

The section of my Vagrantfile that is no longer working looks like this

unless Vagrant.has_plugin?("vagrant-vbguest")
raise 'The Vagrant VBGuest plugin must be install prior to building this VM (vagrant plugin install vagrant-vbguest)'
end

This worked in 2.1.2 and fails in 2.1.4 (I didn't try 2.1.3).

I'm running OS X High Sierra, and the Vagrantfile is trying to create a guest for CentOS - but it doesn't get very far.

Vagrantfile

Vagrant.configure('2') do |config|

  unless Vagrant.has_plugin?("vagrant-vbguest")
    raise 'The Vagrant VBGuest plugin must be install prior to building this VM (vagrant plugin install vagrant-vbguest)'
  end

  config.vm.define 'xxxx-centos-base'
  config.vm.box = 'centos/7'


  config.vm.provider 'virtualbox' do |virtualbox|
    virtualbox.name = 'XXXX Development Base'
    virtualbox.cpus = 2
    virtualbox.memory = 4096
  end

  config.vm.provision 'ansible_local' do |ansible|
    ansible.compatibility_mode = '2.0'
    ansible.playbook = 'xxxx-centos-base.yml'
    ansible.become = true
  end

end
bug core

Most helpful comment

Yes, and my apologies. The project local plugin support was a long time in the making and while I thought I had coverage on the modifications, the .has_plugin? method didn't have the right kind of coverage for the changes. Again, my apologies for the bug and the fix for it will be up as a PR shortly.

All 20 comments

The same on 2.1.3, I temporarily fixed it updating to 2.1.4 and installing the plugin manually with the new --local flag.

Hi,

Thanks for reporting this issue. The root cause of the issue is due to the loading of the Vagrantfile for processing local plugin information which occurs before any plugins have been loaded. I'll investigate how this can be stubbed so the initial load won't cause problems when running plugin checks like this. A couple workarounds in the meantime:

Use local plugins when available:

if Gem::Version.new(Vagrant::VERSION) >= Gem::Version.new("2.1.3")
  config.vagrant.plugins = "vagrant-vbguest"
elsif !Vagrant.has_plugin?("vagrant-vbguest")
    raise 'The Vagrant VBGuest plugin must be install prior to building this VM (vagrant plugin install vagrant-vbguest)'
end

Or wrap the check to allow for the first load:

if $check || Gem::Version(Vagrant::VERSION) < Gem::Version.new("2.1.3")
  unless Vagrant.has_plugin?("vagrant-vbguest")
    raise 'The Vagrant VBGuest plugin must be install prior to building this VM (vagrant plugin install vagrant-vbguest)'
  end
end
$check = true

I'm running into this issue as well. However, I'm wondering about this:

The root cause of the issue is due to the loading of the Vagrantfile for processing local plugin information which occurs before any plugins have been loaded

I know this is the case for earlier versions of Vagrant -- this morning I was running 2.1.2, and when I ran vagrant plugin list in a directory with a Vagrantfile, my Vagrant.has_plugin?() check would always fail because the plugins hadn't been loaded yet. However, I could run vagrant up in the project successfully -- the plugins would be loaded and available.

After updating to Vagrant 2.1.4, working with the same Vagrantfile I find that I can now run vagrant plugin list and get the expected list of installed plugins (probably thanks to #10030 :). But when I run vagrant up in the project, the Vagrant.has_plugin?() fails. I'm experiencing the opposite behavior as compared to under Vagrant 2.1.2.

Based on @andreadelfino's comment about being able to work around this by installing the plugin with the new --local flag, I wonder whether there's something related to the local vs. global plugin contexts happening here.

@becw Yes, the root issue is around the localized plugins which are read out of the Vagrantfile. The unintended consequence being that when the Vagrantfile is first loaded, no plugins have been loaded yet. This is because the project localized plugins are loaded first so the constraints that they provide have precedence over globally available plugins.

Ah, if they're being loaded first -- at what point in the up process are the global plugins available?

The order is roughly:

  1. Vagrant environment is initialized
  2. Vagrantfile is read during initialization
  3. Plugins defined in config.vagrant.plugins are installed if missing
  4. Local plugins are loaded (plugins defined in config.vagrant.plugins)
  5. Global plugins are loaded
  6. Vagrantfile and configuration loaders are reset so they can be reloaded with support for newly loaded plugins

So the problem lies at step 2 where we load to get the list of project local plugins. Because the has_plugin? is checking loaded specs, and no specs have been loaded at this point, it returns false.

Just to clarify -- when you say "Plugins defined in config.vagrant.plugins are installed if missing", is that referring to whatever custom code is run inside that unless Vagrant.has_plugin?("vagrant-vbguest") conditional?

Either way, did this order change as a result of #10030 or #10155? It seems like before 2.1.3/2.1.4, the behavior was something like:

  1. Vagrant environment is initialized
  2. Global plugins are loaded
  3. Vagrantfile is read
  4. ...

... rather than the Vagrantfile being loaded twice (once before any plugins are available, and once after). It sounds like this is pretty entangled with loading local plugins.

The change came in #10037 which introduced support for project specific plugins. I have a pretty clear idea on how this can be managed by simply using the plugin data file for running the check when specs haven't been loaded yet.

@chrisroberts

any ETA for a reliable fix ? quite frankly, IMHO, and _as is_, 2.1.{3,4} releases are busted for the vast majority of vagrant (power) users :-(... if a fix takes long it may be better to just get out the local plugins patch and push a _known_ working version ... (as there are some goodies post 2.1.2 that are handy and telling people to just revert to 2.1.2 until things are sorted simply looks... bad [again just my humble opinion]).

thanks in advance!

Version 2.1.4, broken as noted in this thread, unusable. Downgraded to Version 2.1.2, problem solved.

I do agree with @AntonioMeireles AntonioMeireles, however, on the other hand, thank you developers for a great platform ... looking forward to Version 2.1.5. "Stuff Happens."

Yes, and my apologies. The project local plugin support was a long time in the making and while I thought I had coverage on the modifications, the .has_plugin? method didn't have the right kind of coverage for the changes. Again, my apologies for the bug and the fix for it will be up as a PR shortly.

@chrisroberts no need to apologize. s%ˆ&% happens to us all. just keep the great work and have a great weekend too!

I second @AntonioMeireles - no need to apologize. Vagrant is one of the essential tools in my bag, and I'd much rather report an issue than see it stagnate. Keep up the great work!!

Just came across this after a couple of hours banging my head against the wall.

My Vagrant was pretty out-of-date, so wasn't sure at what point this issue(?) was introduced to revert back...

Having said that, I basically decided to parse the ~/.vagrant.d/plugins.json file to check for the existence of specific installed plugins (rather than has_plugins).

Having said that, @chrisroberts - Am I to understand that there is a (new?) config setting... config.vagrant.plugins = ["vagrant-plugin", "vagrant-other-plugin"]... That will do the same thing as the _famous_ ruby code blocks now? Albeit on a local scale, which is probably better anyway...

Configuring config.vagrant.plugins as mentioned above by @flatline-studios indeed does the trick:

Vagrant.configure(2) do |config|
  config.vagrant.plugins = ["vagrant-bindfs"]
...
Vagrant has detected project local plugins configured for this
project which are not installed.

  vagrant-bindfs
Install local plugins (Y/N) [N]: Y
Installing the 'vagrant-bindfs' plugin. This can take a few minutes...

@flatline-studios, @thanosp Have you found some (official) documentation on this? I clicked through https://www.vagrantup.com/docs/plugins/ but could not find anything.

I'd like to have vagrant automatically attempted an install, so this can run unattended. I've been using this:

if $check # rubocop:disable Style/GlobalVars
  unless Vagrant.has_plugin?("vagrant-s3auth")
    # Attempt to install ourself. Bail out on failure so we don't get stuck in an
    # infinite loop.
    system("vagrant plugin install vagrant-s3auth") || exit!

    # Relaunch Vagrant so the plugin is detected. Exit with the same status code.
    exit system("vagrant", *ARGV)
  end
end
$check = true # rubocop:disable Style/GlobalVars

I'm trying to understand if there is now an official way of doing this…

and there's another question : what will be the canonical way to check and/or enforce the version of local plugins...//cc @chrisroberts

The link @thanosp provided above (https://github.com/hashicorp/vagrant/issues/10161#issuecomment-420573538) is where you can find the configuration options to use within a Vagrantfile for defining project local plugins. Local plugins can be defined simply by name, or can include extra information like version constraints and entry points (path to be used for the require call).

I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings