在 vagrant up 期间在主机上运行脚本

dig*_*tal 45 vagrant

当 vagrant 配置服务器时,我想在主机上运行一个 bash 脚本。

实现这一目标的最佳方法是什么?

小智 34

至少有两个插件应该有帮助:

如果您不关心脚本是否在(几乎)所有vagrant命令上运行,您也可以在 Vagrantfile 中直接退出(或使用任何 ruby​​ 魔法):

system('./myscript.sh')

Vagrant.configure('2') do |config|
  # ...
end
Run Code Online (Sandbox Code Playgroud)

  • Vagrant 触发器看起来正是我需要的。 (2认同)

Mic*_*ick 31

简单(且完整)的解决方案

(我说完整是因为接受的答案不会检查用户是否正在使用 vagrant up。因此,脚本在每个命令上执行,这不是 OP 想要的。)

然而,对此有一个简单的解决方案。

ARGV[0]是命令的第一个参数输入,可以是updownstatus,等。只需选中的值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
Run Code Online (Sandbox Code Playgroud)

  • @CristianoFontes 您可以在系统调用之外的 ruby​​ 中进行 argv 测试,它将在 windows 和 *nix 中工作。我使用它来设置一个全局 ruby​​ 变量,通过在命令行上查找 up 或 provision 命令来指示正在进行配置:if ARGV[0] =~ /^up|provision$/i 而不是 ARGV.include?(" --no-provision") $provisioning = true else $provisioning = false end (3认同)
  • @Mick 它只是来自 Vagrant 文档(https://docs.vagrantup.com/v2/plugins/commands.html)。它还会导致脚本脆弱,因为您无法确定在调用情况下 argv[0] 是“up”而不是一个标志。另外,如果您使用原始的 ruby​​,那么您就有点破坏了框架应该提供的封装。有一些机制可以正确执行此操作,因此恕我直言,您应该尽可能使用这些机制 (2认同)

Joe*_*l B 12

把它放在你的 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
Run Code Online (Sandbox Code Playgroud)

然后像这样简单地在你的 Vagrantfile 中调用:

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

通过这样的命令行:

vagrant provision --provision-with list-files

这是一种 hack,因为它看起来像插件,但实际上不是(当你这样做时它不会出现vagrant plugin list)。我不建议这样做,除非它具有不需要安装插件的优点,因此您的 Vagrantfile 可以在任何支持最新配置版本(撰写本文时的版本 2)的机器上运行。尽管这听起来很有希望移植,但您发出的实际命令也存在整个跨平台问题。如果您希望 Vagrantfile 具有可移植性,则需要考虑,但这应该可以帮助您入门。


小智 12

基于@tmatilai 的回答,但已在 2019 年更新,vagrant-triggers 已合并到 Vagrant。所以你现在可以做这样的事情:

node.trigger.before [:up, :provision] do |trigger|
  trigger.info = "Running ./myscript.sh locally..."
  trigger.run = {path: "./myscript.sh"}
end
Run Code Online (Sandbox Code Playgroud)

这个块在config.vm.define. 更多文档:https : //www.vagrantup.com/docs/triggers/

  • 这是迄今为止最优雅的答案。我应该补充一点,将此代码片段和类似的代码片段放在“config.vm.define”中并不是必需的;它们可以放在 `Vagrant.configure("2") do |config| 中 ...结束`也是如此。最后需要注意的是,在 Windows 主机上,Vagrant 也很乐意执行具有“.ps1”扩展名的 Powershell 脚本。 (2认同)

小智 5

与@tmatilai 关于使用的说法一致

system('./myscript.sh')
Run Code Online (Sandbox Code Playgroud)

我发现它对一次性命令非常有用,例如安装 vagrant 命令或某些可能未安装在系统中的配置程序。我只是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 的第一行。这样,它将首先安装 vagrant-fabric 插件、fabric 和 jinja(如果失败,将首先尝试不使用sudoforvirtualenvs和 with sudo),然后该行注释本身。