Запускать скрипт на хост-машине во время vagrant up

40

Я хотел бы запустить bash-скрипт на хост-машине, когда vagrant подготовит сервер.

Каков наилучший способ достижения этого?

цифровой
источник

Ответы:

29

Как минимум два плагина, которые должны помочь:

Если вас не волнует, что скрипт запускается (почти) для всех vagrantкоманд, вы также можете просто раскошелиться (или использовать какую-либо рубиновую магию) в Vagrantfile:

system('./myscript.sh')

Vagrant.configure('2') do |config|
  # ...
end
tmatilai
источник
2
Бродячие триггеры выглядят именно так, как мне нужно.
цифровой
Где вы нашли эту функцию system ()? Я не могу найти документацию об этом нигде ...
Криштиану Фонтес
1
@CristianoFontes, он находится в Kernelмодуле, задокументирован здесь . KernelМодуль входит в Objectкласс, поэтому его методы доступны во всех областях.
tmatilai
1
Глупый я. Я искал в бродячей документации. Благодарность!
Криштиану Фонтес
26

Простое (и полное) решение

(Я говорю «завершено», потому что принятый ответ не проверяет, использует ли пользователь vagrant up. Поэтому сценарий выполняется для каждой команды, а это не то, что хочет OP).

Однако есть простое решение.

ARGV[0]является первым аргументом команды вошел и может быть up, down, statusи т.д .. Просто проверьте значение ARGV[0]в вашем Vagrantfile.


Что-то вроде этого подойдет:

system("
    if [ #{ARGV[0]} = 'up' ]; then
        echo 'You are doing vagrant up and can execute your script'
        ./myscript.sh
    fi
")

Vagrant.configure('2') do |config|
  # ...
end
Мик
источник
1
Привет, Мик ... Хороший ответ, спасибо за это. Но я не могу получить if [# {ARGV [0]} = 'up']; работать на окнах. Он никогда не находит аргумента
Криштиану Фонтес
1
Это выполняет ваш скрипт первым делом, прежде чем что-либо еще выполняется, независимо от его положения в Vagrantfile. Это может быть достаточно для того, что вы делаете, но мне нужен был плагин
vagrant-triggers
3
@CristianoFontes вы можете выполнить тест argv в ruby ​​вне системного вызова, и он будет работать в windows и * nix. Я использую это, чтобы установить глобальную переменную ruby, указывающую, что инициализация происходит путем поиска команды up или provision в командной строке: если ARGV [0] = ~ / ^ up | provision $ / i, а не ARGV.include? (" --no-provision ") $ provisioning = true иначе $ provisioning = false end
Ревень
На самом деле это плохая практика, как советует Vagrant, вы должны написать плагин для подключения к команде «up», вы можете указать любое из: до, после и вокруг выполнения.
SilentICE
1
@ Мик это только из блуждающих документов ( docs.vagrantup.com/v2/plugins/commands.html ). Это также делает хрупкий скрипт, поскольку вы не можете быть уверены, что в случаях вызова argv [0] имеет значение «up», а не говорит флаг. Кроме того, если вы переходите к необработанному ruby, вы как бы нарушаете инкапсуляцию, которую должна обеспечивать инфраструктура. Существуют механизмы, позволяющие сделать это правильно, поэтому ИМХО, вы должны использовать их, когда это возможно
SilentICE
9

Поместите это в верхнюю часть вашего Vagrantfile:

module LocalCommand
    class Config < Vagrant.plugin("2", :config)
        attr_accessor :command
    end

    class Plugin < Vagrant.plugin("2")
        name "local_shell"

        config(:local_shell, :provisioner) do
            Config
        end

        provisioner(:local_shell) do
            Provisioner
        end
    end

    class Provisioner < Vagrant.plugin("2", :provisioner)
        def provision
            result = system "#{config.command}"
        end
    end
end

Затем просто вызовите в своем Vagrantfile вот так:

config.vm.provision "list-files", type: "local_shell", command: "ls"

И через командную строку вот так:

vagrant provision --provision-with list-files

Это своего рода хак, так как выглядит как плагин, но на самом деле это не так (он не появится, когда вы это сделаете vagrant plugin list). Я не рекомендую делать это таким образом, за исключением того, что он имеет то преимущество, что не требует установки плагина, поэтому ваш Vagrantfile будет работать на любом компьютере, который поддерживает последнюю версию конфигурации (версия 2 на момент написания этой статьи). Хотя это звучит многообещающе переносимо, есть также и кросс-платформенная проблема самой команды, которую вы выдаете. Вам нужно будет учесть, хотите ли вы, чтобы ваш Vagrantfile был переносимым, но это должно помочь вам начать.

Джоэл Б
источник
1
Хороший ответ, я собираюсь использовать это для настройки переадресации низкого порта.
poindexter
6

На основании ответа @ tmatilai, но обновленного до 2019 года, vagrant-триггеры были объединены в Vagrant. Теперь вы можете сделать что-то вроде этого:

node.trigger.before [:up, :provision] do |trigger|
  trigger.info = "Running ./myscript.sh locally..."
  trigger.run = {path: "./myscript.sh"}
end

Этот блок идет внутри config.vm.define. Дополнительная документация: https://www.vagrantup.com/docs/triggers/

Шон Худ
источник
Это самый элегантный ответ на сегодняшний день. Я должен добавить, что размещение этого и подобных фрагментов внутри config.vm.defineне является обязательным требованием; они также могут быть размещены внутри Vagrant.configure("2") do |config| ... end. В заключение отметим, что на хостах Windows Vagrant с удовольствием выполнит сценарии Powershell, которые также имеют .ps1расширение.
Бен Джонсон
4

В соответствии с тем, что @tmatilai сказал об использовании

system('./myscript.sh')

Я нашел это очень полезным для одноразовых команд, таких как установка бродячих команд или какого-либо провайдера, который может быть не установлен в системе. Я просто избегаю его повторного запуска каждый раз, когда я вызываю vagrantкоманды, добавляя sed для автоматического комментирования Vagrantfile.

Например:

system('vagrant plugin install vagrant-fabric && (pip install fabric jinja2 || sudo pip install fabric jinja2) && sed -i -e "s/^system/#system/g" Vagrantfile')

И я делаю это первой строкой моего Vagrantfile. Таким образом , он будет сначала установить бродягу-ткань плагин, ткань и дзиндзя (будет попробовать сначала без sudoна virtualenvsи sudoесли это не удается) , а затем сама линия комментарии.

kenorb
источник
Было бы проще просто составить список плагинов grep, чем раскомментировать Vagrantfile, что может вызвать проблемы у других людей в вашей команде. if [[ $(vagrant plugin list | grep -c vagrant-host-shell) == "0" ]] then vagrant plugin install vagrant-host-shell fi
Джордан
Проблема в том, что он будет запущен другими командами, что если вы запустите vagrant statusраньше vagrant up...
Мик