Skip to content
This repository

Install plugin dependencies from within Vagrantfile #1874

Closed
erran-r7 opened this Issue June 26, 2013 · 37 comments
Erran Carey [Rapid7]

The ability to install plugins programmatically would be beneficial in Vagrantfiles. My idea of how this would work is placing plugin dependencies outside of the Vagrant configure blocks like so:

plugin 'vagrant-berkshelf', '1.3.2'

Vagrant.configure('2') do |config|
  # Normal configuration here
end

Related issues:

I started to create a work around at the top of my Vagrantfile, in accordance with my comment on #1736 , but I only gotten this far (by shelling out and grepping through the vagrant.d directory):

def plugin(name, version = nil, opts = {})
  @vagrant_home ||= opts[:home_path] || ENV['VAGRANT_HOME'] || "#{ENV['HOME']}/.vagrant.d"
  plugins = JSON.parse(File.read("#@vagrant_home/plugins.json"))

  if !plugins['installed'].include?(name) || (version && !version_matches(name, version))
    cmd = "vagrant plugin install"
    cmd << " --entry-point #{opts[:entry_point]}" if opts[:entry_point]
    cmd << " --plugin-source #{opts[:source]}" if opts[:source]
    cmd << " --plugin-version #{version}" if version
    cmd << " #{name}"

    result = %x(#{cmd})
  end
end

def version_matches(name, version)
  gems = Dir["#@vagrant_home/gems/specifications/*"].map { |spec| spec.split('/').last.sub(/\.gemspec$/,'').split(/-(?=[\d]+\.?){1,}/) }
  gem_hash = {}
  gems.each { |gem, v| gem_hash[gem] = v }
  gem_hash[name] == version
end

# With version/source: plugin 'vagrant-berkshelf', '1.3.2', source: 'https://rubygems.org'
plugin 'vagrant-berkshelf'
plugin 'vagrant-omnibus'

To me it looks like the solution would be to expose a similar method while Vagrantfile's are being parsed. This code in VagrantPlugins::CommandPlugin::Command::Install is probably how the plugin method would handle install. I'm not sure how to handle the versioning though.

tknerr
tknerr commented June 27, 2013

@ecarey-r7 I have started some work at vagrant-plugin-bundler. So far it only checks if the plugin requirements are met, but does not automatically install the missing plugin versions yet.

Versioning is a big deal though, since vagrant currently allows a plugin to be installed only in a single version (unlike Gems, which you can have in multiple versions).

As long as this is not fixed, installing the required plugins is a potentially dangerous operation as two parallel vagrant process might interfere each other due to different plugin requirements.

Erran Carey [Rapid7]

@tknerr I'm not sure about the syntax, but that looks great. One thing is the way you're listing plugins, you could download them from JSON (that's what seems to be going on in Vagrant):

  @vagrant_home ||= opts[:home_path] || ENV['VAGRANT_HOME'] || "#{ENV['HOME']}/.vagrant.d"
  plugins = JSON.parse(File.read("#@vagrant_home/plugins.json"))
plugins['installed']

Also, wouldn't the changes better be suited in the core Vagrant library? That is a user manually needs to install the vagrant-plugin-bundler plugin to manage other plugins through their Vagrant file. I could see this being a problem as a plugin that needs to be manually installed:

Vagrant.configure('2') do |config|
  config.plugin deps do
    depend 'vagrant-omnibus', '1.0.2'
    depend 'vagrant-cachier', '0.1.0'
  end
end
[ecarey @ dvwa]$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
There are errors in the configuration of this machine. Please fix
the following errors and try again:

Vagrant:
* Unknown configuration section 'berkshelf'.
tknerr
tknerr commented June 27, 2013

@ecarey-r7 yes, this should be fixed in vagrant core definitely. I see the vagrant-plugin-bunlder plugin as a temporary workaround until then only.

Hope that @mitchellh or @fgrehm will jump in here :-)

Fabio Rehm
Collaborator
fgrehm commented June 27, 2013

TBH I don't think this belongs on vagrant core itself. An analogy would be having this logic from inside Ruby on Rails instead of relying on Bundler, which IMHO does not make sense. Rails just provides the foundation for others to build plugins and relies on Bundler to get things in place and load plugins' code.
But that's just my 2 cents ;)

Erran Carey [Rapid7]

Vagrantfiles already manage boxes, which are a type of dependency. There are two solutions IMO:
1. The previously stated solution, adding some sort of plugin method to the Vagrantfiles either how @tknerr or I described.
2. Create a .vagrant_plugins or Vagrantplugins file which could be used like a Gemfile when invoking bundle install.

You manually need to install plugins regardless with vagrant at the moment:

[ecarey @ dvwa]$ vagrant up
Bringing machine 'standalone' up with 'virtualbox' provider...
Bringing machine 'xampp' up with 'virtualbox' provider...
There are errors in the configuration of this machine. Please fix
the following errors and try again:

Vagrant:
* Unknown configuration section 'berkshelf'.
* Unknown configuration section 'omnibus'.
Erran Carey [Rapid7]

The workflow could then be:

git clone https://github.com/user/repo
cd repo
bundle install # Install dependencies from Gemfile

# Either
vagrant plugin install # (with no args) could install from a new vagrant plugin file.
vagrant up

# Or
vagrant up # Installs boxes and plugins
Fabio Rehm
Collaborator
fgrehm commented June 27, 2013

Just to be clear, I really believe we need some sort of Bundler for Vagrant as there are plugins being created almost every month :P I just don't think it belongs on Vagrant's core :) let's wait for @mitchellh opinion on this

Erran Carey [Rapid7]

I can agree with that. I misunderstood you before. If that route's taken then I still think it'd be great to have a syntax in the Vagrantfile for installing plugins. (option two above)

tknerr
tknerr commented June 29, 2013

@fgrehm agree to the viewpoint that it does not belong to vagrant core, I would compare it with Ruby vs. Bundler.

But: in order to create something similar to bundler we would need the possibility to store multiple versions of the same plugin in parallel. Right now that is not possible as vagrant will automatically uninstall the previous version of a plugin once you install a newer one.

One option as suggested by @thedrow would be to replace the install_gem command with a custom implementation that bypasses the vagrant plugin mechanism and installs vagrant plugins to a separate sandbox.

While this would be the only possibility I see right now, I'm not sure whether this is a good idea or not.

@fgrehm, @mitchellh what do you think?

tknerr tknerr referenced this issue in tknerr/vagrant-plugin-bundler June 29, 2013
Open

Plugins sandbox for each Vagrantfile #10

Omer Katz

Please do note that my suggestion also requires us to replace the uninstallation command so it will uninstall the plugin from the installation path of the sandbox. I know it's obvious but I'm just making sure everyone acknowledged that.
It can lead to nasty bugs otherwise.

Robert (Jamie) Munro

Something like this is a great idea, but I want my non-expert users to be able to do:

git checkout [project url]
cd [project dir]
vagrant up

And the necessary plugins be installed or at least a message like "plugin foobar not found, type vagrant plugin install foobar to install it" be shown to the user.

Extra steps, particularly ones that vary depending on the project, hugely reduce the appeal of vagrant.

Patrick Connolly patcon referenced this issue in fgrehm/vagrant-cachier July 03, 2013
Closed

Reduce requirement for initial plugin config #23

Fabio Rehm
Collaborator
fgrehm commented July 15, 2013

Hey guys, here's my take on the problem: https://github.com/fgrehm/vundler :)

Erran Carey [Rapid7]

@fgrehm Aside from the split second of name confusion I love it. I'm closing this issue as I feel that vundler's a good solution for it.

Erran Carey [Rapid7] erran-r7 closed this July 15, 2013
Fabio Rehm
Collaborator
fgrehm commented July 15, 2013

@ecarey-r7 No worries, I'm up for name suggestions, vagrant-bundler and vagrant-plugin-bundler were taken already and I ran out of ideas :)

Erran Carey [Rapid7]

It's not that I don't like it. I just thought of Vundle for a second. :laughing:

Patrick Connolly
patcon commented July 15, 2013

According to my most trusted source, "vundle" is not a thing:
http://www.urbandictionary.com/define.php?term=vundle

:P

EDIT: Ah...

EDIT2: AWESOME.

Erran Carey [Rapid7]

@patcon I realize you noticed now, but let me google that for you: http://lmgtfy.com/?q=vundle

Patrick Connolly
patcon commented July 15, 2013

:)

Also, throwing in my hat for the new name: #1789 (comment)

Robert (Jamie) Munro

No no no no no no no!!!!!!

Something to do this must go into core.

The whole point of vagrant is that I can type vagrant up and have a working system. Having to install some other product is not an acceptable compromise. I may as well just install the plugins. It's bad enough having to install virtual box as well as vagrant.

Patrick Connolly
patcon commented July 16, 2013

Core could easily be aware of an awesome tool, directing the user toward it, without pulling in the whole kit-and-caboodle. There are alternative ways to address user experience concerns aside from bringing in a potentially large chunk of codebase.

And vagrant uping to get plugins might solve a problem for you, but could just as easily cause the problem for others. (eg. one plugin doesn't work on their system). There are lots of reasons not to force one user's plugins on another.

Erran Carey [Rapid7]

I agree with @patcon. vundler is a good solution. If you disagree @rjmunro the you could always use my hack above.

It changes the workflow from:

  • Install vagrant
  • Install virtualbox
  • In every project with different dependencies:
    • vagrant plugin install vagrant-some-plugin
    • vagrant plugin install vagrant-another-plugin

To:

  • Install vagrant
  • Install virtualbox
  • vagrant plugin install vundler
  • vagrant vundle setup - Only once
  • vagrant plugin bundle - In any project where it's necessary, it even ties into core and warns tells the user that they can just plugin bundle
Greg Elin

I am looking at this issue. Typing vagrant up is magic. Manually installing plugins is like telling the audience to look the other way while the trick is done.

I like magic.

Thomas Welton

I have the same opinion as @rjmunro
I want to be able to tell people. Hey dude just git clone and vagrant up & boom!
Having to explain to people, hey ok so Vagrant is a thing, it does virtual host management. And theres this bindle thing it does plugin management. Install both of these things then boom! isn't as sexy.

And in terms of the Ruby and Bundler comparison, Nodejs ships with NPM by default now. I'd love ti for Vagrant to ship with a tool to manage plugins.

seclorum
Fabio Rehm
Collaborator

Guys, eventually this will come in to core

Regarding "where to find plugins", I've been doing my best to keep this Wiki page up to date and easy to find plugins ;) In fact I have even thought of creating a new category of deprecated / no longer maintained plugins to reduce the noise and save others some trouble, just haven't had the time to do it yet

Patrick Connolly

The ability to "tag" github repos could potentially make the above concern much simpler. (ie. vagrant-plugin tag that we can use the github search api to filter for)

Feel free to :+1: this related issue: isaacs/github#114

stanislav bashkirtsev ctapobep referenced this issue from a commit in jtalks-org/jtalks-vm January 12, 2014
stanislav bashkirtsev Updated the way jtalks-cicd is installed - first we pip-install the m…
…ysql-connector-python because it does not get installed via setuptools by jtalks-cicd package (the mysql package is now hosted on a different host and therefore pip does not trust to it and the installation fails). This is a dirty hack, but our hands are tied here.

Also, added plugins auto-installation according to a workaround listed [on GitHub](mitchellh/vagrant#1874). As for now Vagrant does not support plugin auto-installation out-of-box.
06772d1
suan

Agreed with needing the ability to automatically install needed plugins upon vagrant up. Over here we use vagrant so that some not-too-technical people have an environment to work with. All the extra steps to enter commands to install plugins before they can vagrant up really gets in the way of things.

If there's concern about "pollution" of a user's vagrant install through this mechanism, might I suggest having Vagrant output a prompt like:

Vagrant will now install needed plugins X, Y, and Z. [Y/n]

so the user is aware? This seems to me like a sensible compromise.

Taylor Price

You already can install plugins by just doing a vagrant up... Just shell out in the first lines of the vagrantfile and put in some lines to install plugins/ check if they are already installed.

Greg Elin
Erran Carey

@gregelin If you read my actual issue here you'll see a way to do so. %x(COMMAND HERE) is a way to shell out in Ruby. It holds the exit status and output if you assign it to a variable. My example covers a lot though. It should get you what you need to wrap it up and make it pretty.

Greg Elin

@erran Just looked at example. I'm afraid my Ruby is not strong enough that I immediately follow the example.

The placement of the plugin reference makes sense:

plugin 'vagrant-berkshelf', '1.3.2'

Vagrant.configure('2') do |config|
  # Normal configuration here
end

Less clear to me is where your other code goes. I'm guessing you are recommending the other coded might be a solution for inside of Vagrant's ruby code?

I was hoping by "shell out" there was a way within the Vagrantfile itself to call a shell script that installed plugin. I understand there is a reluctance to do this as Vagrantfile targets the guest machine and having Vagrantfile also target changes on the host machine crosses a logical layer boundary.

Maybe another way to think of this Vagrantfilehost that is a distinct controller for controlling the host machine and the Vagrant environment?

kman007us

Is there a known fix? Using vagrant 1.3.5, I'm running into this error when running vagrant up:

I added "require 'berkshelf/vagrant' to my Vagrantfile, yet I'm sttil getting this error:

unknown configuration section omnibus

Erran Carey
erran commented March 25, 2014

@kman007us vagrant plugin install vagrant-omnibus The berkshelf and omnibus dependencies are separate. You need to pull in the omnibus vagrant plugin to gain the ability to access the omnibus "configuration section".

Taylor Price

@gregelin something like this:

%x(vagrant plugin install vagrant-omnibus) unless Vagrant.has_plugin?('vagrant-omnibus')

That will one line will check if vagrant-omnibus is installed, and if it is not, vagrant will install it for you.

Kurt Zoglmann

@gregelin I ended up doing something like this:

if !Vagrant.has_plugin?('vagrant-omnibus') &&  ENV['SKIP'] != 'true'
  if RUBY_PLATFORM =~ /win/ && RUBY_PLATFORM !~ /darwin/
    puts "The vagrant-omnibus plugin is required. Please install it with \"vagrant plugin install vagrant-omnibus\""
    exit
  end

  print "Installing vagrant plugin vagrant-omnibus..."
  %x(bash -c "export SKIP=true; vagrant plugin install vagrant-omnibus") unless Vagrant.has_plugin?('vagrant-omnibus') || ENV['SKIP'] == 'true'
  puts "Done!"
  puts "Please re-run your vagrant command..."
  exit
end
Greg Elin
Taylor Price

You can also do stuff like this:

if Vagrant::Util::Platform.windows?

instead of using RUBY_PLATFORM

Vincent Murphy vdm referenced this issue in sax/vagrant-smartos-packager April 08, 2014
Merged

vagrant-smartos-zones plugin check and install #2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.