在无所事事期间在主机上运行脚本


40

当无业游民调配服务器时,我想在主机上运行bash脚本。

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

Answers:


29

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

如果您不关心脚本是否(几乎)在所有vagrant命令上运行,则也可以在Vagrantfile中将其外壳(或使用红宝石魔术):

system('./myscript.sh')

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

2
流浪汉触发器看起来正是我所需要的。
数字

您在哪里找到了这个system()函数?我在任何地方都找不到关于它的任何文档...
Cristiano Fontes

1
@CristianoFontes,在Kernel模块中,在此处记录。该Kernel模块包含在Object类中,因此其方法在所有范围内都可用。
tmatilai

1
愚蠢的我。我在寻找无业游民的文档。谢谢!
Cristiano Fontes 2015年

26

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

(我之所以说是完整的,是因为接受的答案不会检查用户是否正在使用无用功。因此,脚本是在每个命令上执行的,这不是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

1
嗨,米克...很好的回答,谢谢。但是如果[#{ARGV [0]} ='up'];我不知道;在Windows上工作。它从来没有找到arg
Cristiano Fontes

1
这将首先执行脚本,然后再执行其他任何操作,而不管其在Vagrantfile中的位置如何。这可能足以满足您的需求,但我需要的是
无用

3
@CristianoFontes,您可以在系统调用之外的ruby中进行argv测试,它将在Windows和* nix中运行。我使用它来设置全局ruby变量,该变量指示正在通过在命令行上查找up或Provisioning命令来进行配置:if ARGV [0] =〜/ ^ up | provision $ / i而不是ARGV.include?(“ --no-provision“)$ provisioning = true else $ provisioning = false end
大黄

根据Vagrant的建议,这实际上是一种不良做法,您应该编写一个插件以挂接到“ up”命令,您可以指定执行以下操作中的任何一个:之前,之后和前后。
SilentICE

1
@Mick仅来自Vagrant文​​档(docs.vagrantup.com/v2/plugins/commands.html)。这也使脚本变得脆弱,因为您无法确定在调用情况下argv [0]是否为'up'而不是发出标志。另外,如果您要使用原始的红宝石,那么您可能会破坏该框架应该提供的封装。有一些机制可以正确执行此操作,因此恕我直言,您应该尽可能使用这些机制
SilentICE 2015年

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 '16

6

根据@tmatilai的答案但已在2019年更新,流浪者触发已合并到流浪者中。因此,您现在可以执行以下操作:

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也会很高兴地执行具有.ps1扩展名的Powershell脚本。
本·约翰逊

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的第一行。这样,它将首先安装vagrant-fabric插件,fabric和jinja(如果没有失败,将首先尝试sudofor virtualenvs和with sudo),然后行注释本身。


简单地grep vagrant插件列表而不是取消注释Vagrantfile会更容易,因为这可能会给团队中的其他人带来麻烦。if [[ $(vagrant plugin list | grep -c vagrant-host-shell) == "0" ]] then vagrant plugin install vagrant-host-shell fi
约旦

问题是,它将在其他命令上触发,如果您vagrant statusvagrant up... 之前运行呢?
Mick
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.