¿Exigir un complemento Vagrant dentro del Vagrantfile?

80

La supuesta ejecución de un Vagrantfilerequiere la instalación de un complemento Vagrant específico. Entonces, básicamente lo que debes hacer es

$ vagrant plugin install foobar-plugin
$ vagrant up

Si omite el primer paso, vagrant upfalla.

¿Existe una opción en Vagrant para que instale el complemento automáticamente? En otras palabras: ¿Es posible especificar dentro de Vagrantfilequé complementos instalar automáticamente antes de crear y arrancar la máquina?

Golo Roden
fuente

Respuestas:

24

Actualización de 2019: Vagrant ahora tiene la funcionalidad para requerir complementos a través de la Vagrantfilevía:

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

Si Vagrant detecta que hay complementos que aún no están instalados, le pedirá al usuario que los instale él mismo:

$ 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.

Ver https://www.vagrantup.com/docs/vagrantfile/vagrant_settings.html

Moritz Gunz
fuente
¿Qué sucede si quisiera omitir el mensaje y autoinstalar todos los complementos necesarios?
pihentagy
67

ACTUALIZACIÓN 31 de agosto de 2018: consulte la corrección de @ Starx a continuación para versiones posteriores de Vagrant (1.8 y superior)

Aquí hay una versión basada en la solución de Louis St. Amour junto con el comentario de Rob Kinyon sobre re-exec si se instaló un nuevo complemento, lo uso con éxito en mi propia configuración:

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
Amos Shapira
fuente
5
Definitivamente la mejor solución en este momento
Anis
1
Actualicé la solución el 20 de abril para usar solo una llamada al "sistema" para instalar todos los complementos faltantes.
Amos Shapira
4
Esto no funcionó. Entró en un ciclo infinito de instalación de complementos. De alguna manera, el nuevo proceso vagabundo no puede recoger los complementos recién instalados en el proceso vagabundo principal
Arif Akram Khan
1
Gracias por la actualización. De hecho, terminé siguiendo la solución sugerida por mkuzmin aquí: github.com/mitchellh/vagrant/issues/4347 . Implica usar un complemento llamado complementos vagabundos y luego usar un código (muy similar al suyo) en Vagrantfile.
Arif Akram Khan
1
@SteveHenty Simpatizo con su comentario, pero mover esto a un complemento anulará el propósito del código (de poder hacerlo la git clone...; cd ...; vagrant upprimera vez).
Amos Shapira
51

Como soy un desarrollador de Ruby y Bindler ya no se mantiene, me pareció más natural escribir un poco de código en la parte superior de mi Vagrantfile para instalar los complementos necesarios si faltan (por ejemplo, antes de la Vagrant.configurelínea)

Lo siguiente funciona para mí:

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

system, a diferencia del uso de comillas invertidas, hará eco del comando en stdout, tal como lo haría al ejecutar el comando usted mismo. Y de esta manera, no necesito otro complemento o sistema con un nombre extraño para realizar un seguimiento de los complementos necesarios que Vagrant puede actualizar de todos modos.

Louis St-Amour
fuente
8
Necesitará 'exec "vagrant # {ARGV.join' '}"' para reiniciar el proceso vagrant con el complemento instalado.
Rob Kinyon
1
Buen punto. En mi caso, recibí un error, pero veo la salida del complemento de instalación y sé que debo volver a ejecutar el comando. Hacer que se vuelva a ejecutar automáticamente sería una mejora aún mejor. Si lo reescribo, tal vez verifique si no se instaló algún complemento, y si es así, instale los complementos primero y luego vuelva a ejecutar el script en lugar de verificar e instalar cada complemento uno a la vez ...
Louis St -Amour
2
Sería increíble tener un Vagrant.has_plugin?comando en el nivel de shell o simplemente vagrant plugin installverificar si el complemento ya está allí.
Sakovias
1
Bueno, siempre puedes hacer algo así, if [ $(vagrant plugin list | egrep 'vagrant-hostsupdater|vagrant-share' -c) == 2 ] ; then echo "All plugins installed." ; else echo "Missing plugin"; fipero hay una razón por la que nadie escribe scripts bash si pueden evitarlo ;-) ¿Quizás experimentar más con el comando del plugin vagabundo?
Louis St-Amour
48

Como señalé en mi respuesta a su otra pregunta , puede usar bindler para instalar un conjunto de complementos específicos para un proyecto usando un solo comando.

Si Bindler está instalado y el complemento requerido no lo está, Bindler generará un error y abortará el proceso. También hay un problema abierto relacionado con la instalación automática de complementos en vagrant ups, pero hasta ahora nadie se ha registrado todavía.

Si no desea utilizar Bindler, puede utilizar Vagrant.has_plugin?(disponible en 1.3.0+) en la parte superior de su Vagrantfiley error si el complemento requerido no está instalado.

Algo como:

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

ACTUALIZACIÓN : Bindler ya no es compatible y el núcleo de Vagrant no ha proporcionado ninguna funcionalidad equivalente a partir del 11 de mayo de 2015

fgrehm
fuente
14
Para los futuros empleados de Google, tenga en cuenta que esta respuesta está un poco desactualizada. Ahora puede especificar sus dependencias en Gemfileun :pluginsgrupo que Vagrant comprobará. Vea mi respuesta a continuación para obtener más detalles.
Jonathan Bender
2
Gemfileestá destinado al desarrollo de complementos de Vagrant. Ver github.com/mitchellh/vagrant/issues/8370
mixel
10

Tenga en cuenta que a partir de Vagrant 1.5, puede especificar sus dependencias en su Gemfile. Según la publicación del blog sobre la actualización :

Ahora, Vagrant 1.5 cargará automáticamente cualquier gema en el grupo "complementos" en su Gemfile. Como ejemplo, aquí está el Gemfile para un complemento "vagrant-bar":

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
Jonathan Bender
fuente
8
¿No se refiere esa publicación de blog al desarrollo de complementos de Vagrant ? Las cajas de Vagrant generalmente no tienen Gemfiles, usan Vagrantfiles.
Don McCurdy
1
Tiene razón en que las cajas de Vagrant no tienen Gemfiles per se (podría tener un Vagrantfile que no requiera ningún complemento), pero si está utilizando complementos (el contexto del blog era como dependencias para su propio complemento, pero lo mismo vale verdadero para Vagrantfiles), debe usar un Gemfile para especificar esos requisitos.
Jonathan Bender
7
Gracias, eso es útil. Dado que muchos usuarios de Vagrant no son desarrolladores de ruby ​​y aún no tienen un Gemfile, ¿te importaría explicar cómo lo configuraste? Creé uno similar a su ejemplo, pero vagrant upno carga nada automáticamente. Intenté, bundle installpero eso está dando un mensaje sobre los permisos de Rubygems del sistema, que no suena bien.
Don McCurdy
1
Supongo que está trabajando en OSX usando la instalación de ruby ​​estándar y se encuentra con este problema: stackoverflow.com/questions/14607193 ?
Jonathan Bender
1
En el mundo de los libros de cocina para chefs, muy pocos tendrán un archivo de gemas
mr.buttons
6

No pude agregar un comentario a la respuesta de Louis St-Amour, pero quería publicar esto en caso de que alguien necesitara ayuda para extender su solución.

# 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
James Reimer
fuente
//, Tenga vagrant-listen cuenta que en lo anterior hay un ejemplo de un complemento, no una parte necesaria del código. Puede ver otros complementos de Vagrant aquí: vagrant-lists.github.io
Nathan Basanese
3

En la nueva versión de Vagrant, la respuesta de @Amos Shapira se atasca en un bucle infinito. La razón de esto es que cada llamada a vagrant plugin installtambién procesa el Vagrantfiley cuando se procesa ejecuta el código relacionado con la instalación del complemento una y otra vez y así sucesivamente.

Aquí está mi solución que evita el bucle.

# 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
Starx
fuente
1

Acabo de notar aquí http://docs.vagrantup.com/v2/plugins/packaging.html una instrucción

Vagrant.require_plugin "vagrant-aws"

que hace exactamente lo mismo que lo que describió fgrehm: generar rápidamente un error si el complemento no está instalado.

Hasta donde yo sé, todavía no hay forma de instalar complementos automáticamente

Julien
fuente
6
Vagrant.require_plugin ya no se utiliza en 1.5 +
EIS
1
Aquí está la publicación del blog oficial sobre la desaprobación: vagrantup.com/blog/vagrant-1-5-plugin-improvements.html Según mi conocimiento limitado, quedó en desuso porque ya no es necesario, Vagrant ahora verificará automáticamente las dependencias de los complementos. Sin embargo, no estoy completamente seguro de haber entendido la publicación del blog ...
Jeff Widman
La publicación habla sobre la verificación automática de las dependencias de los complementos , pero no he visto nada sobre las dependencias del cuadro Vagrant en sí.
Don McCurdy
Vagrant.require_plugines obsoleto. Comprobado con Vagrant 1.7.4.
czerasz
1

Mi respuesta está muy cerca de la respuesta de Louis St-Amour , pero en lugar de instalar complementos automáticamente, solo genera un mensaje de error, por lo que el usuario tiene que instalar el complemento manualmente.

Preferiría que los usuarios estén al tanto de los complementos que se instalan, porque se aplican globalmente a todas las instancias de Vagrant, no solo al Vagrantfile actual.

Coloque en la parte superior de Vagrantfileuna línea como esta para cada complemento, en este ejemplo vagrant-vbguest,:

 raise "vagrant-vbguest plugin must be installed" unless Vagrant.has_plugin? "vagrant-vbguest"
Flimm
fuente
1

Podrías usar este proyecto (soy el autor): https://github.com/DevNIX/Vagrant-dependency-manager

Se basa en respuestas similares pero tratando de ser más completo y estable. La gran ventaja de esta idea es que puede distribuir su Vagrantfile y se ejecutará en todas las computadoras independientemente de los complementos instalados en ese entorno.

Es fácil de usar:

  1. Copie dependency_manager.rb junto a su Vagrantfile
  2. Inclúyalo y llame check_pluginspasando sus dependencias como una matriz

    Ejemplo:

    # -*- 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. ¡Lucro!

Me encantaría fusionar solicitudes de extracción, solucionar cualquier problema que pudiera tener y obtener ideas de nuevas funciones. Actualmente estoy pensando en actualizar el administrador de dependencias en sí mismo y requerir versiones de complementos específicas: D

¡Saludos!

Dev_NIX
fuente
0

Tengo un problema con la nueva instalación de Vagrant, donde aún no se ha creado el directorio .vagrant.d. Pude hacer que el fragmento de Luis St. Amour funcionara al detectar la excepción.

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

begin
    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
rescue
    exec "vagrant #{ARGV.join(' ')}"
end
Guillaume Hardy
fuente
En Windows, esto me da el error "Trayendo la máquina 'predeterminada' con el proveedor 'virtualbox' ... pero otro proceso ya está ejecutando una acción en la máquina" porque uplo está ejecutando up. ¿Hay alguna forma de evitar esto sin ejecutar vagrant updos veces?
Tom B
0

Esto es lo que estoy usando en Vagrant 1.8 y funciona bien. Pon esto en algún lugar antes del bloque de configuración en tu Vagrantfile.

# install required plugins if necessary
if ARGV[0] == 'up'
    # add required plugins here
    required_plugins = %w( plugin1 plugin2 plugin3 )
    missing_plugins = []
    required_plugins.each do |plugin|
        missing_plugins.push(plugin) unless Vagrant.has_plugin? plugin
    end

    if ! missing_plugins.empty?
        install_these = missing_plugins.join(' ')
        puts "Found missing plugins: #{install_these}.  Installing using sudo..."
        exec "sudo vagrant plugin install #{install_these}; vagrant up"
    end
end
lps
fuente
Parece que no es multiplataforma.
thorr18