在Vagrantfile中要求安装一个Vagrant插件?

85

执行一个 Vagrantfile 需要安装特定的 Vagrant 插件。因此,基本上你需要做的是

$ vagrant plugin install foobar-plugin
$ vagrant up

如果你跳过第一步,vagrant up 将失败。

Vagrant 中是否有选项可以自动安装插件?换句话说:是否可以在 Vagrantfile 中指定要在创建和启动虚拟机之前自动安装的插件?

12个回答

66

更新于2018年8月31日:有关Vagrant的更新版本(1.8及以上),请参见@Starx下面的修复

这里是基于路易斯·圣·阿摩尔(Louis St. Amour)的解决方案和罗布·金扬(Rob Kinyon)的评论,如果安装了新插件,则重新执行它。我在自己的设置中成功使用它:

required_plugins = %w(vagrant-share vagrant-vbguest...)

plugins_to_install = required_plugins.select { |plugin| not Vagrant.has_plugin? plugin }
if not plugins_to_install.empty?
  puts "Installing plugins: #{plugins_to_install.join(' ')}"
  if system "vagrant plugin install #{plugins_to_install.join(' ')}"
    exec "vagrant #{ARGV.join(' ')}"
  else
    abort "Installation of one or more plugins has failed. Aborting."
  end
end

5
目前绝对是最好的解决方案。 - Anis
1
我已于4月20日更新了解决方案,仅使用一个“系统”调用来安装所有缺失的插件。 - Capt. Crunch
4
无法正常运作,陷入了安装插件的无限循环中。新的vagrant进程无法获取父进程中新安装的插件。 - Arif Akram Khan
1
感谢更新。实际上,我最终采用了mkuzmin在此处建议的解决方案:https://github.com/mitchellh/vagrant/issues/4347。它涉及使用名为vagrant插件的插件,然后在Vagrantfile中使用一些代码(与您非常相似)。 - Arif Akram Khan
1
@SteveHenty 我理解你的评论,但将其转移到插件中会有点违背代码的初衷(只需在第一次 git clone...; cd ...; vagrant up 即可)。 - Capt. Crunch
显示剩余7条评论

50

由于我是Ruby开发者,而Bindler不再维护,所以我觉得最自然的做法就是在我的Vagrantfile顶部编写一些代码来安装所需的插件(例如,在Vagrant.configure行之前)。

以下方法适用于我:

required_plugins = %w( vagrant-hostmanager vagrant-someotherplugin )
required_plugins.each do |plugin|
  system "vagrant plugin install #{plugin}" unless Vagrant.has_plugin? plugin
end

system 与使用反引号不同,它将命令回显到标准输出(stdout),就像你自己运行命令一样。这种方式不需要再使用另一个奇怪的插件或系统来跟踪所需的插件,因为 Vagrant 可以更新它们。


8
你需要执行 "vagrant #{ARGV.join' '}" 命令,以便在安装插件后重新启动 vagrant 进程。 - Rob Kinyon
1
好主意。在我的情况下,我遇到了一个错误,但是看到了安装插件的输出并知道重新运行命令。自动重新运行将是更好的改进。如果要重新编写它,也许我会检查是否安装了任何插件,如果没有,则先安装插件,然后重新运行脚本,而不是逐个检查和安装每个插件... - Louis St-Amour
2
在Shell级别上拥有Vagrant.has_plugin?命令或者只需通过vagrant plugin install检查插件是否已存在,这将非常棒。 - sakovias
1
你可以尝试这样做:if [ $(vagrant plugin list | egrep 'vagrant-hostsupdater|vagrant-share' -c) == 2 ] ; then echo "All plugins installed." ; else echo "Missing plugin"; fi,但是如果有其他选择的话,没有人会写bash脚本的。也许可以进一步尝试vagrant插件命令? - Louis St-Amour

49

正如我在回答你另一个问题时 指出的那样, 你可以使用bindler通过一个命令安装一组特定于项目的插件。

如果已经安装了bindler但所需的插件未安装,bindler将报错并中止进程。此外,还有一个相关的问题涉及在vagrant up时自动安装插件,但迄今为止还没有人签名参与。

如果您不想使用bindler,您可以在Vagrantfile的顶部使用Vagrant.has_plugin?(1.3.0+可用)并在所需的插件未安装时报错。

像这样:

unless Vagrant.has_plugin?("vagrant-some-plugin")
  raise 'some-plugin is not installed!'
end

Vagrant.configure("2") do |config|
  config.vm.box = "box-name"
end

更新:Bindler已不再支持,截至2015年5月11日,Vagrant核心也没有提供相应的功能。


14
未来的谷歌用户请注意,这篇答案有点过时了。现在您可以在您的 Gemfile 中指定依赖项,并将它们放在一个 :plugins 组下,Vagrant 将会检查这个组中的内容。请看下面的答案获取更多细节。 - Jonathan Bender
2
Gemfile 旨在用于 Vagrant 插件开发。请参阅 https://github.com/mitchellh/vagrant/issues/8370 - mixel

34

2019年更新:Vagrant现在可以通过 Vagrantfile 要求插件功能:

Vagrant.configure("2") do |config|
  config.vagrant.plugins = "vagrant-some-plugin"

  # or as array:
  config.vagrant.plugins = ["vagrant-some-plugin", "vagrant-some-other-plugin"]

  # or as hash
  config.vagrant.plugins = {"vagrant-some-plugin" => {"version" => "1.0.0"}}
end

如果Vagrant检测到有未安装的插件,它会提示用户自行安装:

$ vagrant up
Vagrant has detected project local plugins configured for this
project which are not installed.

  vagrant-some-plugin
Install local plugins (Y/N) [N]: y
Installing the 'vagrant-some-plugin' plugin. This can take a few minutes...
Fetching vagrant-some-plugin-1.0.0.gem
Installed the plugin 'vagrant-some-plugin (1.0.0)'!


Vagrant has completed installing local plugins for the current Vagrant
project directory. Please run the requested command again.

请查看https://www.vagrantup.com/docs/vagrantfile/vagrant_settings.html


3
如果我想跳过提示并自动安装所有必需的插件,该怎么办? - pihentagy

11
请注意,从Vagrant 1.5开始,您可以在Gemfile中指定依赖项。根据更新的博客文章

Now, Vagrant 1.5 will automatically load any gems in the "plugins" group in your Gemfile. As an example, here is the Gemfile for a "vagrant-bar" plugin:

source "https://rubygems.org"

group :development do
  gem "vagrant",
    git: "https://github.com/mitchellh/vagrant.git"
end

group :plugins do
  gem "vagrant-foo",
  gem "vagrant-bar", path: "."
end

9
这篇博客文章不是在讲Vagrant的插件开发吗?一般来说,Vagrant虚拟机并没有Gemfile文件,而是使用Vagrantfile文件。 - Don McCurdy
1
你是正确的,Vagrant boxes 没有 Gemfiles(你可以有一个不需要任何插件的 Vagrantfile),但是如果你正在使用插件(该博客的上下文是作为你自己插件的依赖项,但对于 Vagrantfiles 同样适用),你应该使用一个 Gemfile 来指定这些要求。 - Jonathan Bender
7
谢谢,这很有帮助。由于许多使用Vagrant的用户不是Ruby开发人员,他们可能没有 Gemfile 文件,所以你能解释一下如何设置它吗?我创建了一个类似于你示例的文件,但 vagrant up 并没有自动加载任何内容。尝试过 bundle install 但会提示系统Rubygems权限的问题,这听起来不太对。 - Don McCurdy
1
在厨师食谱的世界中,很少会有一个Gemfile。 - mr.buttons
1
对于那些想知道如何创建Gemfile的人,一旦通过gem install bundler安装了bundle命令,您应该能够使用bundle init在当前目录中创建一个(相对空白的)Gemfile。这些gems可以是git repos或rubygems,甚至是git repos的分支或标记为特定版本/提交,并使用bundle install为该特定文件夹或应用程序的gem要求进行安装。我不知道它们如何与Vagrant一起使用,只是想分享一些背景信息。 - Louis St-Amour
显示剩余3条评论

6

无法对Louis St-Amour的答案添加评论,但我想发布这篇文章以帮助那些需要扩展他的解决方案的人。

# Check for missing plugins
required_plugins = %w(vagrant-list)
plugin_installed = false
required_plugins.each do |plugin|
  unless Vagrant.has_plugin?(plugin)
    system "vagrant plugin install #{plugin}"
    plugin_installed = true
  end
end

# If new plugins installed, restart Vagrant process
if plugin_installed === true
  exec "vagrant #{ARGV.join' '}"
end

//注意,上面的vagrant-list只是一个插件示例,而不是代码的必要部分。您可以在此处查看其他Vagrant插件:http://vagrant-lists.github.io/ - Nathan Basanese

3
在新版本的Vagrant中,@Amos Shapira的答案会陷入无限循环。原因是每次调用vagrant plugin install时都会处理Vagrantfile,并在处理时再次执行与安装插件相关的代码,如此反复进行。

这里是我的解决方案,避免了循环。
# Plugins
#
# Check if the first argument to the vagrant
# command is plugin or not to avoid the loop
if ARGV[0] != 'plugin'

  # Define the plugins in an array format
  required_plugins = [
    'vagrant-vbguest', 'vagrant-hostmanager', 
    'vagrant-disksize'
  ]         
  plugins_to_install = required_plugins.select { |plugin| not Vagrant.has_plugin? plugin }
  if not plugins_to_install.empty?

    puts "Installing plugins: #{plugins_to_install.join(' ')}"
    if system "vagrant plugin install #{plugins_to_install.join(' ')}"
      exec "vagrant #{ARGV.join(' ')}"
    else
      abort "Installation of one or more plugins has failed. Aborting."
    end

  end
end

1
我的答案与Louis St-Amour's answer非常接近,但它不会自动安装插件,而是会引发错误消息,以便用户必须手动安装插件。
我宁愿让用户知道已安装的任何插件,因为它们适用于所有Vagrant实例,而不仅仅是当前的Vagrantfile。
Vagrantfile顶部为每个插件添加一行,例如:vagrant-vbguest
 raise "vagrant-vbguest plugin must be installed" unless Vagrant.has_plugin? "vagrant-vbguest"

1

您可以使用这个项目(我是作者):https://github.com/DevNIX/Vagrant-dependency-manager

它基于类似的答案,但试图更完整和稳定。这个想法的巨大优势是,您可以分发您的Vagrantfile,并且它将在每台计算机上运行,而不管该环境中安装的插件。

它很容易使用:

  1. Copy dependency_manager.rb next to your Vagrantfile
  2. Include it and call check_plugins passing your dependencies as an array

    Example:

    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    
    require File.dirname(__FILE__)+"./dependency_manager"
    
    check_plugins ["vagrant-exec", "vagrant-hostsupdater", "vagrant-cachier", "vagrant-triggers"]
    
    Vagrant.configure(2) do |config|
    
      config.vm.box = "base"
    
    end
    
  3. ???

  4. Profit!

我很乐意合并拉取请求,修复任何可能出现的问题,并获取新功能的想法。目前我正在考虑更新依赖管理器本身,以及要求特定的插件版本:D
问候!

1

我刚注意到这里 http://docs.vagrantup.com/v2/plugins/packaging.html 有一条指示

Vagrant.require_plugin "vagrant-aws"

这个功能与fgrehm所描述的完全一致:如果插件未安装,则快速引发错误。

据我所知,仍然没有自动安装插件的方法。


6
Vagrant.require_plugin 已在1.5版本及以上停止使用,建议使用其他替代方案。 - eis
1
这是关于弃用的官方博客文章:https://www.vagrantup.com/blog/vagrant-1-5-plugin-improvements.html据我所知,它被弃用是因为它不再必要,Vagrant现在会自动检查插件依赖项。但我并不完全确定我是否理解了博客文章... - Jeff Widman
这篇文章谈到了自动检查插件依赖关系,但我还没有看到有关Vagrant box本身依赖关系的任何内容。 - Don McCurdy
Vagrant.require_plugin 已经被弃用。已经在 Vagrant 1.7.4 中进行了检查。 - czerasz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接